山pの楽しいお勉強生活

勉強の成果を垂れ流していきます

Google Apps Script(GAS)のメモ

久しぶりにGASを触ったらかなり忘れていたのでメモ。

Logger.log("ログ出力");
function log(m) {
  var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId());
  var sheet = ss.getSheetByName("log"); // シートの名前
  sheet.appendRow([new Date(), m]);
  Logger.log(m)
}
  • コードフォーマット
    • Tab
  • 値取得
var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId());
var sheet = ss.getSheetByName("シート名"); // シートの名前
var value = sheet.getRange("a1").getValue();
  • メール送信
GmailApp.sendEmail("example@example.com", "タイトル", "本文");
  • fromとかccとかhtmlmailとか
GmailApp.sendEmail("example@example.com", "タイトル", "本文",{from:"from@example.com",cc:"cc@example.com",htmlBody:"<p>htmlmail</p>" });

エンジニアとしてスカウトされたので色々話しを聞いてみた

概要

3/18にFacebookアドレスにいきなりスカウトメールが届く。内容は以下のような感じ。

ある企業のご依頼による求人に見合う方をお探しする中で、
WEB上の公開情報でyamap様のことを拝見し、ぜひお会いしたいと考え、
スカウトのお声掛けでご連絡をさせて頂きました。
  • ↑でyamapとなっている所は本名でした。(Facebookは本名登録してます。) 今は転職する気なんてないですが、何度かメールをやりとりしたら転職に興味なくても、業界の事、転職の事、何でも聞いていいよという事だったので、ネタになるかと思い会ってみる事にしました。

聞きたかったこと

  • 何故私に声がかかったのか。
    • スカウトがかかるほどの技術者であるとは思えない。
  • blogやTwitterからならまだわかるが、何故Facebookから声をかけたのか。
    • Facebookはほぼ見るだけで投稿は皆無。
    • 技術的な事はほぼ呟いていない。
    • また、blogやTwitterでは本名や、Facebookに繋がる情報は出していないはず。
  • 私の現在の能力でどの位の給料が貰えるのか。
  • 転職市場で求められている技術は何か。
  • Groovyは転職市場で評価されているのか。(評価対象になっているのか)

質問と回答

色々あってメモとれなかったので記憶ベースで記載。 括弧内は私の感想です。

  • 何故私にメールを?
    • blogや勉強会の参加履歴を見るとそれなりに価値があると判断した。(正直ふわっとしてた)
  • 私の場合、Facebookからblogなどの情報は辿れないと思うがどうやってみつけたの?
    • IDから色々な情報を集め、その一つに以前の勤務先が残っていた。
    • それを元にFacebookで検索し、アイコンが同じであるため特定。
  • どのような情報からスカウトする相手を探しているのか。
    • ブログ、github、勉強会参加歴、slideshare、等々(←の情報は印刷してきてくれた。)
  • 一番求められているのは言語は何?
  • Android系?
    • Androidもあるが、それ以外の方が多い。
  • Rubyが人気なイメージあるが?
    • 最近はかなり多くなっているが以前Javaが人気。
  • JavaRubyはどの位の差がある?(Javaがまだ一番需要あるとは以外だった)
  • JavaScriptはどう?
    • クライアントサイドは需要がかなりある。
  • サーバ側のJavaScript、node.jsとかはどう?
    • あまり聞かない。
  • C#は?
    • そこそこ。スマホゲームのサーバ側で使用されている印象。(そうなの?)
  • Scalaは?
    • 求めている企業は増えてきている。
    • が、エンジニア自体が少ないのでJavaできればOKというところが多い。
  • Groovyは?
    • 殆ど聞かないが、1社ある。(ここに突っ込んで聞いてたら、後ほどメールがきて数社の情報くれました。)
  • Javaの企業だとJavaフレームワークとか関連技術とかJavaの周辺技術での要求は?
    • 特にない。(ほんとかよ!)
    • 高いJavaの技術。
  • 高いJavaの技術とは具体的には?
    • 特に良いわかりやすい回答はなし。(企業内の面接で判断してるのか?)
  • JavaFXは?
    • 希望してる企業は聞いたことない。
  • COBOLは?
    • 担当ではないので詳しくはわからないが、少ないと思う。
  • PHPは?
    • 最近減ってきていると聞いている。
  • 言語以外だとどういうものに需要がある?
    • AWSAWSの話はこの後も結構出てきた。)
    • Docker
    • Chef
    • 自動化に興味のある企業が多い。(そういえばVagrantの名前が出てこなかった。)
    • サーバサイドだけではなくクライアントができるエンジニア。
  • Gitは必須?
    • できれば尚良いが、必須ではない。
  • 福利厚生とかどう?
    • 当然企業ごとそれぞれ違うが、福利厚生があるからそこにするというほどの差はない。
  • 残業は?
    • 大体はそれなりにある。
  • 残業代が100%出るとことかどの位?
    • ほとんどない。というかない。みなし残業で35~40hがほとんど。
  • ぶっちゃけ年収450なんですが、話に乗ったら上がる?
    • 500、550なら可能。(即答された。けど、私の技術なんてわかるわけないので、この程度の年収なら売り方次第では普通に売れるって事なのかな?)
  • 1日何人と会ってるの?
    • 仕事している人が多いので1日1人会えればいい方。1週間で5人位。
  • 会って話して、転職する!って人いる?
    • 殆どいないが、それなりにはいる。(やはりこの業界はある程度は常に転職考えているのかな?)
  • 会った人から後日連絡とかある?
    • 後日連絡があって紹介することは結構多い。
  • 紹介される場合どういうフローになるの?
    • 面接の前に面談(会社のエンジニアと)をして、お互いに雰囲気掴んだ後に面接というパターンが多い。
  • 友人がスカウトの人から会社にいきなり電話が着たという事を言っていたが、そういうことはあるのか。
    • スカウト会社によるが、Web上にメールなどの連絡先がどうしても見つからず、所属している会社だけがわかっている状況ならばありえる。
  • 電話に出た人にスカウト会社だとわかったら繋いでもらえないのでは?
    • 嘘の会社名は言わないが、会社の略称(ABCとかXYZとかアルファベット数文字)で名乗る。
  • スカウトして成功したらどの位儲けになるの?
    • 転職が決まった方の3ヶ月分の給料を企業から頂く。
  • エージェントと変わらない気がするけど儲かるの?
    • 依頼された際、調査料的な感じで最初に費用を頂く。
  • 依頼は決められた期間に何人紹介するとかノルマあるの?
    • 大体はある。(ニッチな技術な場合はない場合もあるらしい)
  • 景気いい?
    • エンジニアは不足しているので依頼はかなり多い。
    • 紹介するエンジニアが足りていない。
  • こんな時間まで仕事して、土日もエンジニアと会うとなると、休み少ないような?
    • 休みはかなり少ない。大変。(スカウトの人は結構疲れてたw)

(思い出したら随時追加予定)

ぼんやりとしたまとめ

  • 特に私が凄いから声がかかったわけではない。(笑)
  • エンジニアを探す過程の話を聞いてたら、ある程度Web上にアウトプットしている人は声がかかっていると思われる。
  • 向こうは仕事なので結構感じはいい。
  • 匿名と思ってWebに公開している情報でも意外と本名と繋がる。(画像検索とかもするらしい)
  • 転職する際には転職エージェントに声かけると共に、スカウトの人にも連絡するといいのかも。
  • 話はかなり面白かったので暇な人は会ってみると面白いと思う。
  • 割りとニッチな技術でも探せば仕事として触れるっぽい。
  • AWSは触っといた方がいいっぽい。
  • サーバサイドJavaScriptにそれほど食いつきがなかったのは意外。
  • 新宿の喫茶店はコーヒーが1000円弱する。(おかわりは300円。ちなみに奢ってくれた)
  • スカウト業界は景気いいらしい。
  • ↑には書いてないけど、私に紹介しようとした仕事は広告出している会社数社。広告出す所は人不足??

Google Apps ScriptでGoogleスプレッドシートの内容をメールする

概要

会社のメールがGoogle Appsになったので、スプレッドシートやらGoogleドライブと色々連携を試しています。
で、連携をするために使用するのがGoogle Apps Script(略称GAS)ですが、殆どJavaScriptなので超簡単!
とりあえず、スプレッドシートで作った簡易的な進捗管理をメールで送信するようなGASを作成してみました。
実際にはGASは定期的に実行する機能もあるので、毎日朝8~9時に送信するようにしています。

仕様

No. やること 担当 進捗 期日 備考
1 あれをやる 田中 ちょっとだけ 2015/04/25 がんばる
2 これをやる 鈴木 完了 2015/03/25 すぐやる
3 それをやる 高橋 半分くらい 2015/04/15 そのうち
  • 送信されるメール

f:id:yamap_55:20150323022454j:plain

スプレッドシート及びGASのサンプル

※このGASはスプレッドシートに紐付いてないので、動きません。(SpreadsheetApp.getActiveSpreadsheet()がnull)

コード

var MAIL_ADDRESS = "example@example.com";
function myFunction() {
    var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId());
    var sheet = ss.getSheetByName("進捗一覧"); // シートの名前
    
    // 進捗が100%以外のタスクのIndexを取得
    var index = getHeadIndex(sheet, "進捗");
    var range = sheet.getRange("a1");
    var items = [];
    for(i=0;i<sheet.getLastRow();i++) {
      if(range.offset(i, index).getValue() != "完了") {
        items.push(i);
      }
    }
    var style = " style='border:1px #000000 solid;border-collapse:collapse;'";
    var tableList = [];
    tableList.push("<p>タスク一覧</p>");
    
    //データを取得し、HTMLのテーブルを作成。
    tableList.push("<table" + style + ">");
    for(i=0;i<items.length;i++) {
      // iは行のIndex
      var study = [];
      for(j=0;j<sheet.getLastColumn();j++) {
        // jは列のIndex
        var value = range.offset(items[i], j).getValue();
        
        if(Object.prototype.toString.call(value) == "[object Date]") {
          value = formatDate(value);
        } else {
          value = value.toString().replace("\n", "<br/>");
        }
        study.push(value);
      }
      tableList.push("<tr" + style + "><td" + style + ">" + study.join("</td><td" + style + ">") + "</td></tr>");
    }
    tableList.push("</table>");
    
    GmailApp.sendEmail(MAIL_ADDRESS, "進捗連絡", "body", {htmlBody : tableList.join("\n")});
}

/**
 * 指定された名前のHeadを検索し、Indexを返す
 */
var getHeadIndex = function(sheet, name) {
  var range = sheet.getRange("a1");
  for(i=0;i<sheet.getLastColumn();i++) {
    if(range.offset(0, i).getValue() == name) {
      return i;
    }
  }
};

// DateをYYYY/MM/DD形式に変換する
var formatDate = function(date) {
  var format = 'YYYY/MM/DD';
  format = format.replace(/YYYY/g, date.getFullYear());
  format = format.replace(/MM/g, ('0' + (date.getMonth() +1)).slice(-2));
  format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
  return format;
};

まとめ

上のコードはテーブルで表示させているのでやたら長くなっていますが、データ取得するだけ、メール送るだけなら簡単!
Gmailメインの人はプライベートでも色々使っていけるのかも。

参考


追記(2016/12/22)

単純にメールすればどうすれば良いの?っとコメントいただいたのでシンプルなものを追記します。
各メソッドなどは公式リファレンスを参照してください。

仕様

スプレッドシート

No. やること 担当
1 あれをやる 田中
2 これをやる 鈴木
3 それをやる 高橋

送信されるメール

f:id:yamap_55:20161222124541j:plain

コード

var MAIL_ADDRESS = "example@example.com";

function myFunction() {
  var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId());
  var sheet = ss.getSheetByName("進捗"); // シートの名前
  var lastRowIndex = sheet.getLastRow();
  
  var range = sheet.getRange(2, 1, lastRowIndex - 1, 3);
  var values = range.getValues();
  
  var bodyList = values.map(function(value, index) {
    return ("No : " + value[0] + "\nやること : " + value[1] + "\n担当 : " + value[2]);
  });
  GmailApp.sendEmail(MAIL_ADDRESS, "進捗連絡", bodyList.join("\n"));
}

bootstrap2.3.2においてaタグを使用したボタンで、Clickイベントでdisabledを設定するとhrefの設定が動作しない。

QA@ITに投稿したのですが、一応blogにも記載。

概要

bootstrap2.3.2においてaタグを使用したボタンで、Clickイベントでdisabledを設定するとhrefの設定が動作しない。 言葉で説明すると複雑なので再現手順及びコードを記載しました。

  • bootstrap2.3.2を使用し、aタグのボタンを作成。
  • aタグのhrefに何らかの処理を設定。
  • jQueryでaタグのClickイベントでaタグをdisabledにする。(2重処理対策)
  • ボタンをクリックする。
    • 通常はClickイベントが動作し、ボタンがdisabledになり、hrefの設定が動作する。
    • IE8の環境ではClickイベント後、ボタンがdisabledになった後、hrefの設定が動作しない。

サンプル

JS Bin

IEhttp://jsbin.com/duxiki/1/を開いてボタンをクリックすると、IE9以上では「click」、「href」というアラートがそれぞれ1回ずつ表示されますが、IE8(ドキュメントモードで8にしても再現可能。)では「click」のアラートしか表示されません。 -

コード

  • ↑のコードと同じです。IE9以上では「click」、「href」というアラートがそれぞれ1回ずつ表示されますが、IE8(ドキュメントモードで8にしても再現可能。)では「click」のアラートしか表示されません。

  • html

<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" type="text/css" />
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <a id="atag" class="btn" href="javascript:alert('href')">CLICK ME</a>
  </body>
</html>
$("#atag").on("click",function(){
  alert("click");
  $(this).attr('disabled', true);
});

解決方法

問題点

  • aタグにdisabled属性は存在しないため、bootstrapがそれっぽく動作するようにしてくれているが、IE8の場合は対応しきれていないというのが問題か?
  • bootstrapの挙動からみる予想としては。。。bootstrap内でaタグのボタンのクリックイベントで、クリックイベント発生時にdisabledが設定されている場合、return falseを返す的な処理がclickイベントで行われているのでしょうが、 IE8についてはボタンクリック時ではなく、その時点でのdisabled属性を見てしまっているのではないか。(コードは見ていません。。。)

対処方法

  • disabled属性を付与するのではなくあくまでもaタグとして、2重処理を防ぐ。
  • つまり、Clickイベント内で2度目の処理だった場合にはfalseを返せばOK。

サンプル

JS Bin

コード

  • html
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" type="text/css" />
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <a id="atag" class="btn" href="javascript:alert('href')">CLICK ME</a>
  </body>
</html>
$("#atag").on("click",function(){
  if(!$(this).hasClass('disabled')) {
    alert("click");
    $(this).addClass("disabled");
  } else {
    return false;
  }
});

まとめ

  • bootstrapを使うとaタグもいい感じにボタンっぽくしてくれるけど、あくまでもaはaとして扱う必要がある。
  • bootstrapも万能ではない。
  • 細かく分析して問題点を把握する。(最初はjQueryも疑っていた)
  • IE8はクソ。(サポートが切れるのは2016/1/12。)

WindowsでJVM言語「Golo」を使ってみた。

はじめに

JVM上で実行できる動的言語「Golo 2.0」リリース という記事を今更ながらしって、どんなんだろう?っとググったけど、試してる人すらみつからなかったので試してみる。

  • The Golo Programming Languageの最初を適当に実行しています。
  • 最初のみなのでGolo独自機能などは触っていません。
  • ほぼコードしか読んでいません。そもそもあめりか語は殆どわからないので、間違っていたら指摘してください。
  • ごろー

インストール

c:\>cd c:\work\20150211\golo-2.0.0\bin
c:\work\20150211\golo-2.0.0\bin>golo version
2.0.0

HelloWorld

直接ファイルから実行

  • 公式にでかでかと乗っているHelloWorldをコピーして、helloworld.goloとして保存。(拡張子は適当。)
module hello.World

function main = |args| { 
  println("Hello world")
}
  • golo golo --files ${ファイルPATH}」で実行。
c:\work\20150211>golo-2.0.0\bin\golo golo --files ./helloword.golo
Hello world
  • もし、引数を渡したい場合には「--args」をつけるらしい
  • コード
module hello.World

function main = |args| {
  foreach arg in args {
    println(arg)
  }
}
  • 実行
c:\work\20150211>golo-2.0.0\bin\golo golo --files ./hellowordWithArgs.golo --args hello world hoge huga
hello
world
hoge
huga

コンパイルして実行

  • コンパイル(--output付けることでディレクトリを指定。)
c:\work\20150211>golo-2.0.0\bin\golo compile --output classes helloword.golo
  • 実行。
c:\work\20150211>cd classes
c:\work\20150211\classes>..\golo-2.0.0\bin\golo run --module hello.World
Hello world

変数

  • letvarがある。
    • letは固定値。
    • varは再導入可能な変数。
  • コンパイルエラー
module hoge

function main = |args| {
  let h = 1
  println(h)
  h = 2
  println(h)
}
c:\work\20150211>golo-2.0.0\bin\golo golo --files ./hoge.golo
[error] In Golo module: hoge.golo
[error] Assigning `h` at {line=6, column=3} but it is a constant reference
module hoge

function main = |args| {
  var h = 1
  println(h)
  h = 2
  println(h)
}
  • intStringで型指定を試してみたけど型は指定できないみたい。
module hoge

function main = |args| {
  int h = 1
  println(h)
}
c:\work\20150211>golo-2.0.0\bin\golo golo --files ./hoge.golo
[error] In Golo module: hoge.golo
[error] Assigning to either a parameter or an undeclared reference `h` at (line=4, column=7)
[error] Undeclared reference `int` at {line=4, column=3}
[error] Undeclared reference `h` at {line=5, column=11}

  • Javaの型は普通に使えるみたい。
  • Collectionは結構面白い。
  • コード
module hoge

function main = |args| {
  var tuple = [1, 2, 3] # gololang.Tuple
  println("tuple : " + tuple)
  var array = array[1, 2, 3] # Object[]
  println("array : " + array)
  var list = list[1, 2, 3] # LinkedList
  println("list : " + list)
  var vector = vector[1, 2, 3] # ArrayList
  println("vector : " + vector)
  var set = set[1, 2, 3] # LinkedHashSet
  println("set : " + set)
  var map = map[[1, "a"], [2, "b"]] # LinkedHashMap
  println("map : " + map)
  var range = [1..10] # gololang.Range
  println("range : " + range)
}
  • 実行結果
c:\work\20150211>golo-2.0.0\bin\golo golo --files ./hoge.golo
tuple : tuple[1, 2, 3]
array : [Ljava.lang.Object;@5b0a1d2d
list : [1, 2, 3]
vector : [1, 2, 3]
set : [1, 2, 3]
map : {1=a, 2=b}
range : range(1,10)

コメント

  • 行コメントは//ではなくて#
  • ドキュメントコメントは----で囲えばいいらしい。
    • マークダウンで書くといいって書いてあるけど、Document生成した時いい感じにしてくれるのかな?

関数定義

  • listに対してfilterとかmapとかで関数を渡すことが可能。
module hoge

function main = |args| {
  println(list[1, 2, 3, 4]: filter(|n| -> (n % 2) == 0)) # [2, 4]
  println(list[1, 2, 3]: map(|n| -> n * 10)) # [10, 20, 30]
}
  • 関数の合成も可能。
module hoge
function main = |args| {
  let f = |x| -> x + 1
  let g = |y| -> y * 10
  let h = f: andThen(g)
  println(h(1)) # (1 + 1) *10 = 20

  let adder = |x, y| -> x - y
  let add2 = adder: bindAt(1, 2)    # adderのyに2を設定
  println(add2(5)) # 5 - 2 = 3
}

EasyMockでvoidメソッドの振る舞いを定義する方法。

EasyMockで普通のメソッドと同じようにvoidのメソッドの振る舞いを定義しようとしたらハマったのでメモ。(いくつか情報は出たものの、意味がわかりづらかった。)

回答

  • 普通のメソッドのように定義すると「EasyMock のメソッド expect(T) は引数 (void) に適用できません」とエラーになります。
  • よって、一度振る舞いを定義したいメソッドを呼び出した後に「expectLastCall()」を呼ぶことでその呼出を記録することができます。
  • 詳細は以下のサンプル参照。
    • 比較用にvoid以外のメソッドの振る舞いも同時に定義しています。
// テスト対象クラス
public class Hoge {
        // 返り値がString
    public String methodA() {
        return "methodA";
    }

        // 返り値がvoid
    public void methodB(String str) {
    }
}

// テストクラス
public static class HogeTest {
    @Test
    public void testMethod() throws Exception {
        Hoge hogeMock = createMock(Hoge.class);

                // 返り値がStringの場合。
        expect(hogeMock.methodA()).andReturn("mockMethodA"); 

                // 返り値がvoidの場合。
        hogeMock.methodB("str"); // 一回処理を呼び出す。
        EasyMock.expectLastCall(); // 一つ前の挙動を記録する。

        replay(hogeMock);

        assertThat(hogeMock.methodA(), is("mockMethodA"));
        hogeMock.methodB("str"); // str以外の値の場合に例外。

        verify(hogeMock);
    }
}

※上記例はEasyMock Class Extensionが入っている状態での例になります。(使用しないとインターフェースのみ。)

参考

2014年の反省

2014年もそろそろ残りが少なくなってきました。 っということで、2014年の目標の達成度と反省をしようかと。

2014年の目標と結果

勉強会に参加したらblogを書く

  • 今年は9回の勉強会に参加して、8回のblogを書きました。
  • 書いていない1回は11月末のJavaFX勉強会以外は全て記載。
  • JavaFX勉強会はプライベートと仕事共に忙しい時期でいっぱいいっぱいだったのですが、メモはとっていたので少しでも時間見つけて書くべきだったと反省。
  • その他の書いた記事もメモレベルでしか書けていないので、今後はもう少し見れる形で公開するようにしたいです。
  • ただ、去年1年では46記事も書けていたので、blogを書く習慣をつけるというサブ目標はほぼ達成に近いかなと。
  • 良い習慣なので、来年も継続していきたいですな。

Gitを日常的に使う

  • 会社でGitLab導入中で、社内ハッカソンでGitHubを使用というのが実績か。
  • 正直日常的とは言いがたいが、通常操作位はなんとか出来るくらいまでは出来たかなという印象。
  • 来年はGitLabを運用に乗せて行くので、来年いっぱいでは日常的に使っているようになるはず。。。

目標以外の成果

総括

  • 目標は必ず達成できるレベルで設定しているのに、これは残念な結果。後、一押しが足りない。
  • 目標以外もイマイチ。
  • ただ、個人的には今年はよく頑張った感があるのが不思議。
  • 来年も目標はたてるので、しっかりと最後まで意識していきたい。