カメニッキ

カメとインコと釣りの人です

gormのUpdateColumnsでモデル内のboolゼロ値(false)を持ったカラムが更新されなかった の続き

前回の記事(http://tapira.hatenablog.com/entry/2017/08/09/173718)で以下の通りよくわからんくて飛ばしてたところを、gormのコードを追ってみた。

func (s DB) UpdateColumns(values interface{}) DB { ここで呼ばれたタイミングではvaluesに値が渡ってきてるけど、その後instanceにセットしてcallback呼んだタイミングで消えてるので、 Setするどっかのロジックでゼロ値だとスキップするような動きがあると思うけどどこかわからんかった・・・


  • UpdateColumns の呼び出し
db.Model(&eventExBefore).UpdateColumns(&eventExAfter)
  • gorm/callback_update.goのinit関数にて、assignUpdatingAttributesCallbackがコールバック関数に登録されます
// Define callbacks for updating
func init() {
  DefaultCallback.Update().Register("gorm:assign_updating_attributes", assignUpdatingAttributesCallback)
  • その後callCallbacksの呼び出しによって、登録されたコールバック関数が実行されます
func (s *DB) UpdateColumns(values interface{}) *DB {
  return s.clone().NewScope(s.Value).
    Set("gorm:update_column", true).
    Set("gorm:save_associations", false).
    InstanceSet("gorm:update_interface", values).
    callCallbacks(s.parent.callbacks.updates).db
}
  • assignUpdatingAttributesCallbackの中身
// assignUpdatingAttributesCallback assign updating attributes to model
func assignUpdatingAttributesCallback(scope *Scope) {
  if attrs, ok := scope.InstanceGet("gorm:update_interface"); ok {
    if updateMaps, hasUpdate := scope.updatedAttrsWithValues(attrs); hasUpdate {
      scope.InstanceSet("gorm:update_attrs", updateMaps)
    } else {
      scope.SkipLeft()
    }
  }
}

以下の処理で UpdateColumns(&eventExAfter) で渡された値をupdate_attrsにセットしている

    if updateMaps, hasUpdate := scope.updatedAttrsWithValues(attrs); hasUpdate {
      scope.InstanceSet("gorm:update_attrs", updateMaps)
  • updatedAttrsWithValuesの中を追いかけてみると、以下
func (scope *Scope) updatedAttrsWithValues(value interface{}) (results map[string]interface{}, hasUpdate bool) {
  if scope.IndirectValue().Kind() != reflect.Struct {
    return convertInterfaceToMap(value, false), true
  }

  results = map[string]interface{}{}

  for key, value := range convertInterfaceToMap(value, true) {
    if field, ok := scope.FieldByName(key); ok && scope.changeableField(field) {

ゼロ値の場合convertInterfaceToMapにて該当カラムが更新対象列から消える - convertInterfaceToMapは以下

func convertInterfaceToMap(values interface{}, withIgnoredField bool) map[string]interface{} {
  var attrs = map[string]interface{}{}

  switch value := values.(type) {
  case map[string]interface{}:
    return value
  case []interface{}:
    for _, v := range value {
      for key, value := range convertInterfaceToMap(v, withIgnoredField) {
        attrs[key] = value
      }
    }
  case interface{}:
    reflectValue := reflect.ValueOf(values)

    switch reflectValue.Kind() {
    case reflect.Map:
      for _, key := range reflectValue.MapKeys() {
        attrs[ToDBName(key.Interface().(string))] = reflectValue.MapIndex(key).Interface()
      }
    default:
      for _, field := range (&Scope{Value: values}).Fields() {
        if !field.IsBlank && (withIgnoredField || !field.IsIgnored) {
          attrs[field.DBName] = field.Field.Interface()
        }
      }
    }
  }
  return attrs
}
  • 今回はinterface{}で値を受けており、ゼロ値が渡されたカラムは以下の処理でfalseと判定され、更新対象リストにアペンドされていないっぽい
        if !field.IsBlank && (withIgnoredField || !field.IsIgnored) {
          attrs[field.DBName] = field.Field.Interface()
        }
  • 確認してみるとゼロ値のカラムについてはIsBlank=trueとなっていた。IsBlankのセットは以下のコードでやっているぽい
func (field *Field) Set(value interface{}) (err error) {
・・・
field.IsBlank = isBlank(field.Field)
  • isBlankの実装を見てみると
func isBlank(value reflect.Value) bool {
  switch value.Kind() {
  case reflect.String:
    return value.Len() == 0
  case reflect.Bool:
    return !value.Bool()
  case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    return value.Int() == 0
  case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    return value.Uint() == 0
  case reflect.Float32, reflect.Float64:
    return value.Float() == 0
  case reflect.Interface, reflect.Ptr:
    return value.IsNil()
  }

  return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
}

!value.Bool() false渡したらisBlank=true …

bool型がtrueかfalseしかもてない以上、こうなるのはやむないのか。 ここにたどり着くのにめちゃくちゃ時間かかってしまった。 もっと素早くコードリーディングできるようになりたい

今回お世話になったツール

Visual Studio Code(Mac版)のデバッグ機能

gormのUpdateColumnsでモデル内のboolゼロ値(false)を持ったカラムが更新されなかった

schema

mysql> desc events;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int(10)      | YES  |     | NULL    |       |
| name  | varchar(255) | YES  |     | NULL    |       |
| flag  | tinyint(1)   | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

問題

type Event struct {
  Id   uint   `json:"id"`
  Name string `json:"name"`
  Flag bool  `json:"flag"`
}

func gormConnect() *gorm.DB {
  db, err := gorm.Open("mysql", "root@tcp(localhost:3306)/sample")

  if err != nil {
    panic(err.Error())
  }
  return db
}

func hoge(c echo.Context) {
        db := gormConnect()

        // 初期データ作成
        eventEx := Event{Id: 1, Name: "taro", Flag: true}
        result := db.Create(eventEx)
        fmt.Println(result)

        // 初期データのID=1を更新する
        eventExBefore := Event{Id: 1}
        db.First(&eventExBefore)

        eventExAfter := new(Event)
        // {Name: "jiro", Flag: false} という値がPUTされてきたとする
        c.Bind(eventExAfter)
        db.Model(&eventExBefore).UpdateColumns(&eventExAfter)
}

Createのタイミングで以下のINSERT文が発行される

INSERT INTO `events` (`id`,`name`,`flag`) VALUES (1,'taro',1);

Updateで以下のSQL発行を期待するが、、、

UPDATE `events` SET `name` = 'jiro', `flag` = 0  WHERE `events`.`id` = 1;

実際には以下のSQLが発行される

UPDATE `events` SET `name` = 'jiro'  WHERE `events`.`id` = 1;

以下のとおり、bool型ゼロ値ではないtrueを指定すると

func main() {
        db := gormConnect()

        // 初期データ作成
        eventEx := Event{Id: 1, Name: "taro", Flag: true}
        result := db.Create(eventEx)
        fmt.Println(result)

        // 初期データのID=1を更新する
        eventExBefore := Event{Id: 1}
        db.First(&eventExBefore)

        eventExAfter := new(Event)
        // {Name: "jiro", Flag: true} という値がPUTされてきたとする
        c.Bind(eventExAfter)
        db.Model(&eventExBefore).UpdateColumns(&eventExAfter)
}

期待どおり動作する

INSERT INTO `events` (`id`,`name`,`flag`) VALUES (1,'taro',0);
UPDATE `events` SET `name` = 'jiro', `flag` = 1  WHERE `events`.`id` = 1;

なんでこうなるのか

func (s *DB) UpdateColumns(values interface{}) *DB { ここで呼ばれたタイミングではvaluesに値が渡ってきてるけど、その後instanceにセットしてcallback呼んだタイミングで消えてるので、
Setするどっかのロジックでゼロ値だとスキップするような動きがあると思うけどどこかわからんかった・・・
追記 以下でした

tapira.hatenablog.com

以下のように map[string]interface{}{} に更新パラメータをバインドさせてUpdateすれば意図した動きになるが、Structに定義されたカラム全てが載ってしまい、思った使い方ができなかった。

event := map[string]interface{}{}
    if err := c.Bind(&params); err != nil {
        return err
    }

期待どおりに動かすには

boolポインタ型を使用する。

--- a/gorm-sample.go
+++ b/gorm-sample.go
@@ -10,7 +10,7 @@ import (
 type Event struct {
        Id   uint   `json:"id"`
        Name string `json:"name"`
-       Flag bool   `json:"flag"`
+       Flag *bool  `json:"flag"`
 }

 func gormConnect() *gorm.DB {
@@ -24,15 +24,17 @@ func gormConnect() *gorm.DB {

 func main() {
        db := gormConnect()
+       ptrue := &[]bool{true}[0]
+       pfalse := &[]bool{false}[0]

        // 初期データ作成
-       eventEx := Event{Id: 1, Name: "taro", Flag: false}
+       eventEx := Event{Id: 1, Name: "taro", Flag: ptrue}
        result := db.Create(eventEx)
        fmt.Println(result)

        // 初期データのID=1を更新する
        eventExBefore := Event{Id: 1}
        db.First(&eventExBefore)

        eventExAfter := new(Event)
        // {Name: "jiro", Flag: false} という値がPUTされてきたとする
        c.Bind(eventExAfter)
        db.Model(&eventExBefore).UpdateColumns(&eventExAfter)
 }

こうするとboolポインタ型のゼロ値はnilとなり、falseと値を指定した場合も意図した動きになる。

        eventExAfter := map[string]interface{}{}
        // {Name: "jiro", Flag: false} という値がPUTされてきたとする
        c.Bind(eventExAfter)
        db.Model(&eventExBefore).UpdateColumns(&eventExAfter)

ちなみに、この挙動は github.com/go-playground/validator を使用した際にも同じだった。 flag: falseと指定していた場合もrequire指定でエラーになってしまう。

uintなどを使用した場合にもゼロ値が 0 であるため、0で更新したい場合などは↑のようにuintポインタ型にしないとだめそう。 他にうまい回避方法がわからなくて、こんなことしたけど実はイケてるやり方があったら知りたい。。。

PHPカンファレンス福岡2017のスポンサーセッションで「mrubyで作る海外IPフィルター」という話をした

スライド

speakerdeck.com

発表の振り返り

  • 思ったよりも落ち着いて喋ることができた
  • 正面を向いて話すよう意識できたのはよかった
  • 本番よりも練習の方が話しづらい。本番はむしろやりやすい(重要)
  • 練習大事…本当に練習大事

スライド作成の振り返り・今後意識したいこと

  • プロジェクターの画面比率は早めに確認しよう
    • 16:9で作ってたのを大至急4:3にして辛い思い
  • カンファレンスの雰囲気・規模・どういった立場で喋るのか意識しよう
    • スポンサーセッションは固めの文章、明るくやるならトーク
    • 小規模なLTなどであればフレンドリーな文面も可 など
  • どういった層を相手に話すか意識しよう
    • 技術レベル
    • 使う言葉が一般的なのか、内輪向けの話なのか、単語の定義を意識
  • どういうタイトル何が言いたいか をまず決めよう
  • スライドの流れ・ストーリーを意識しよう
    • 守らないと結局何が言いたいの?なスライドになる
  • スライド作成前にアウトラインを固めよう
    • トーリー作りがスライドだとやり辛い、めちゃくちゃなものができやすい
    • スライドへでのレビューは面倒(レビュワーへの負担)
  • 箇条書きは一行で。改行避ける
  • 文章で伝えづらいところだけ図にしよう
    • わかりやすくするための図がわかりにくい問題
  • テーマを統一しよう
    • いろんな画像混ぜない
  • 文字はでかいほどよい
  • 自分自身で読み直す時必ず声に出したほうが問題に気づきやすい
  • プロジェクタにうつしてレビューするとただ眺めるだけよりも多くの問題見えてくる

(※あくまでも僕個人の思い)

PHPカンファレンス運営スタッフの皆様、スライドづくりのご協力いただいたペパボの皆様、当日セッションを見に来てくれた方、ありがとうございました!!!

.
.
.
.
.
.
.
.
.
.
.
.
.
(おまけ)keynote発表者ディスプレイをカスタマイズ の残り時間設定が罠だった…w
15:00 で15分じゃなくて15時間… どんなプレゼンだw f:id:tapira:20170610175007p:plain

MacBook Pro 2016 late 13inch Tach Bar搭載モデルの社外充電器

スペック f:id:tapira:20170528232007p:plain

以下のAnker製品で問題なく充電できました ※充電できることを保証するわけではない

Anker PowerLine+ USB-C & USB-C ケーブル (0.9m) 新しいMacBook / Nexus 5X / Nexus 6P他対応 https://www.amazon.co.jp/gp/product/B01GNQXIMG/ref=oh_aui_detailpage_o03_s00?ie=UTF8&psc=1

Anker PowerPort+ 5 USB-C Power Delivery (60W 5ポート Power Delivery搭載 USB&USB-C 急速充電器) 新しいMacBook / iPhone / iPad / Android 各種他対応 A2053511 https://www.amazon.co.jp/gp/product/B01C8LM7Y0/ref=oh_aui_detailpage_o03_s00?ie=UTF8&psc=1

正規品の半額くらいか。

mgemテンプレート作成からDocker上でビルドまで

こんばんは。最近mgemを作成する機会があり、何から始めたらいいのかわからなくて困ったので、一連の流れをまとめて備忘録にしたいと思います。 本作業はMacOSX Siera上で実施しています。 誤った記述があれば突っ込んでいただけると・・・

mgemとは?

非常にざっくりいうとCRubyの gem のmruby版が mgem CRubyのように gem install hoge するわけではなく、mgemでは依存ライブラリとして指定したうえで mruby自身のコンパイル時に組み込み、 hoge mgemを組み込んだmrubyバイナリ を作ることになる。


さっそく作る

1. matsumotory/mruby-mrbgem-template を使用してmgemの雛形を作成する

詳細は http://blog.matsumoto-r.jp/?p=3923 など参照 基本的にリポジトリのREADME通りにやればOK

# リポジトリもってくる
tahira at mac in ~/work
❯ git clone git@github.com:matsumotory/mruby-mrbgem-template.git                                                                                                                                           23:57
Cloning into 'mruby-mrbgem-template'...
remote: Counting objects: 126, done.
remote: Total 126 (delta 0), reused 0 (delta 0), pack-reused 126
Receiving objects: 100% (126/126), 20.05 KiB | 0 bytes/s, done.
Resolving deltas: 100% (59/59), done.

tahira at mac in ~/work
❯ cd mruby-mrbgem-template/                                                                                                                                                                             3s 106ms

# template_config.rbを編集する
tahira at mac in ~/work/mruby-mrbgem-template on master
❯ vi template_config.rb
tahira at mac in ~/work/mruby-mrbgem-template on master
❯ cat -n template_config.rb                                                                                                                                                                             29s 69ms
     1 params = {
     2   :mrbgem_name    => 'mruby-example',
     3   :license        => 'MIT',
     4   :github_user    => 'tap1ra',
     5   :mrbgem_prefix  => File.expand_path('.'),
     6   :class_name     => 'Example',
     7   :author         => 'tap1ra',
     8 }
     9
    10 c = MrbgemTemplate.new params
    11 c.create
# rake実行 いろいろ走って mruby-example が作成される
# 完了するとその後叩くコマンドも全部出力される
tahira at mac in ~/work/mruby-mrbgem-template on master [?]
❯ rake
  cd /Users/tahira/work/mruby-mrbgem-template/mruby-example # ★これがmgemを作成していくリポジトリ
  git init
  git add .
  git commit -m "first commit"
  git remote add origin git@github.com:tap1ra/mruby-example.git
  git push -u origin master

  > finally, pull-request mruby-example.gem to mgem-list https://github.com/bovi/mgem-list

# あらかじめ自身のGithubアカウントに mruby-example リポジトリを作成し、上記コマンドを実行していく
tahira at mac in ~/work/mruby-mrbgem-template on master [?]cd /Users/tahira/work/mruby-mrbgem-template/mruby-example                                                                                                                                            33s 125ms

tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯   git init                                                                                                                                                                                               00:03
Initialized empty Git repository in /Users/tahira/work/mruby-mrbgem-template/mruby-example/.git/

tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯   git add .                                                                                                                                                                                              00:03

tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [+]
❯   git commit -m "first commit"                                                                                                                                                                           00:03
[master (root-commit) 451b629] first commit
 10 files changed, 188 insertions(+)
 create mode 100644 .travis.yml
 create mode 100644 .travis_build_config.rb
 create mode 100644 LICENSE
 create mode 100644 README.md
 create mode 100644 mrbgem.rake
 create mode 100644 mrblib/mrb_example.rb
 create mode 100644 mruby-example.gem
 create mode 100644 src/mrb_example.c
 create mode 100644 src/mrb_example.h
 create mode 100644 test/mrb_example.rb

tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master
❯   git remote add origin git@github.com:tap1ra/mruby-example.git                                                                                                                                          00:03

tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master
❯   git push -u origin master

# これでmgemの雛形がリポジトリにpushされた

2. 雛形のなかみ

# 何も手を加えていない状態が以下
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master
❯ ls -la                                                                                          00:24
total 48
drwxr-xr-x  12 tahira  2033490572   408  5 19 00:03 .
drwxr-xr-x  18 tahira  2033490572   612  5 19 00:00 ..
drwxr-xr-x  12 tahira  2033490572   408  5 19 00:24 .git
-rw-r--r--   1 tahira  2033490572   329  5 19 00:00 .travis.yml
-rw-r--r--   1 tahira  2033490572   121  5 19 00:00 .travis_build_config.rb
-rw-r--r--   1 tahira  2033490572  1135  5 19 00:00 LICENSE
-rw-r--r--   1 tahira  2033490572   504  5 19 00:00 README.md
-rw-r--r--  1 tahira  2033490572   110  5 19 00:00 mrbgem.rake # 作成するmgemが依存する他のmgemの情報を記載するファイル
drwxr-xr-x  3 tahira  2033490572   102  5 19 00:00 mrblib  # この下に作成するmgemのmrubyソースコードを配置
-rw-r--r--  1 tahira  2033490572   181  5 19 00:00 mruby-example.gem
drwxr-xr-x  4 tahira  2033490572   136  5 19 00:00 src     # この下に作成するmgemのCソースコードを配置
drwxr-xr-x   3 tahira  2033490572   102  5 19 00:00 test

3. 手元でビルドできるようRakefileを作成する

# .travis_build_config.rb と [https://github.com/pyama86/mruby-acme-client/blob/master/build_config.rb] などを真似して自身を組み込んだmrubyをビルドできるようbuild_config.rbを作成する
# 多少違うかもしれないけど以下のようになっているはず
❯ cat .travis_build_config.rb                                                                     00:10
MRuby::Build.new do |conf|
  toolchain :gcc
  conf.gembox 'default'
  conf.gem '../mruby-example'
  conf.enable_test
end
# 「conf.gem '../mruby-mrbgem-template'」この行で依存gemとして自分自身を読ませている(認識違ったら突っ込んで…)
# よって以下のようなbuild_config.rbを書く
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ cat -n build_config.rb                                                                       9s 854ms
     1 MRuby::Build.new do |conf|
     2   toolchain :gcc
     3   conf.gembox 'default'
     4   conf.gem File.expand_path(File.dirname(__FILE__))
     5   conf.enable_test
     6 end
# その上で「build_config.rbに↑で作成したものを利用してmrubyをビルドする」タスクの定義をおこなう
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ cat -n Rakefile                                                                                 00:33
     1 MRUBY_CONFIG=File.expand_path("build_config.rb")
     2 MRUBY_VERSION="master"
     3 desc "mrubyをビルドするタスク"
     4 file :mruby do
     5   sh "git clone --depth=1 git://github.com/mruby/mruby.git"
     6   Dir.chdir("./mruby") do
     7     sh "git checkout #{MRUBY_VERSION} || true"
     8   end
     9 end
    10 
    11 desc "build_config.rbを指定して(指定しないとmruby標準のものが利用されるので)ビルドするタスク"
    12 task :compile => :mruby do
    13   sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} rake all"
    14 end

4. ここまでやるとmruby-exampleを組み込んだmrubyのビルドができるのでタスクを実行する

tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ rake compile                                                                                    209ms
git clone --depth=1 git://github.com/mruby/mruby.git
Cloning into 'mruby'...
remote: Counting objects: 468, done.
remote: Compressing objects: 100% (377/377), done.
remote: Total 468 (delta 35), reused 216 (delta 13), pack-reused 0
Receiving objects: 100% (468/468), 474.67 KiB | 68.00 KiB/s, done.
Resolving deltas: 100% (35/35), done.
git checkout master|| true
Already on 'master'
Your branch is up-to-date with 'origin/master'.
cd mruby && MRUBY_CONFIG=build_config.rb rake all
・・・(中略)
ビルド完了
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ ll mruby/bin/mruby                                                                              00:36
-rwxr-xr-x  1 tahira  2033490572  920760  5 19 00:35 mruby/bin/mruby

# mruby-exampleで定義されたクラスは以下のようになっている
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ cat mrblib/mrb_example.rb                                                                       00:36
class Example
  def bye
    self.hello + " bye"
  end
end

# 以下のようなテストファイルを用意して作成したmrubyバイナリで実行すると、mrubyバイナリにmruby-exampleが組み込まれていれば結果が出力される
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ cat -n example.rb                                                                               10:30
     1 example = Example.new('hoge')
     2 p example.bye
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ mruby/bin/mruby example.rb                                                                      10:30
"hoge bye"

# mruby-exampleが組み込まれていなければ以下のようにclass定義がみつからずエラーになる
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ mruby/bin/mruby example.rb                                                                1m 7s 814ms
trace:
    [0] example.rb:1
example.rb:1:uninitialized constant Example (NameError)

5. Linux上で実行できるバイナリを作るため、Dockerでビルドさせる

今回Mac上で作業したので、アーキテクチャが異なるため(?)Linux上では実行することができません (同様にLinux上でビルドしたものはMac上で実行しようとすると「cannot execute binary file」のように怒られます)

# 以下のようなDockerfileを作成します
# centos latestを使用し、ビルドに必要なライブラリをインストールしているだけのきれいな環境
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ cat -n Dockerfile                                                                      13s 155ms
     1 FROM centos:latest
     2
     3 RUN yum install -y \
     4   epel-release \
     5   gcc \
     6   git \
     7   openssl-devel \
     8   ca-certificates \
     9   rubygems \
    10   curl \
    11   bison
    12
    13 RUN gem install \
    14   mgem \
    15   rake
# Rakefileに以下のようにdockerでビルドするためのタスクの定義をおこないます
# 1. ↑で作成したDockerfileを使用してexample:mrubyコンテナを作成
# 2. mruby-example作業ディレクトリをdockerコンテナ上にバインドマウントさせ、あとはMac上で行うときと同様にrake compileタスクを実行しています
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ cat -n Rakefile | tail -4                                                                             20s 100ms
    16 task :build do
    17   sh "docker build -t example:mruby ."
    18   sh "docker run -v `pwd`:/tmp -w /tmp -t example:mruby rake compile"
    19 end
# rake buildタスクを実行すると無事mrubyバイナリが作成されました
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?]
❯ rake build                                                                                      10:39
docker build -t example:mruby .
Sending build context to Docker daemon 23.23 MB
Step 1/3 : FROM centos:latest
# 今ビルドしたものをMac上で実行すると、おこられます
❯ mruby/bin/mruby example.rb                                                                  54s 699ms
Failed to execute process 'mruby/bin/mruby'. Reason:
exec: Exec format error
The file 'mruby/bin/mruby' is marked as an executable but could not be run by the operating system.

今回はmgem自身の実装は全く触れていませんが、とりあえず開発ができる準備ができました。 おしまい


(便利情報)

(2017/05/19 16:09追記) github.com

テンプレート作成時にRakefileも標準で作成されるようにPRして、マージされました!!