mruby_tools 0.0.3.1 → 0.0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9d06a51f1ed9667b7b39c12bcb3173f4b064d6ad
4
- data.tar.gz: e63a21a002b71f1aef930fb5f91950e90757e7c3
3
+ metadata.gz: 74d761a22e0d9e61ab9da0ea9204690c938b45f4
4
+ data.tar.gz: 6f4a0f440ce7638f058b4b7631b22c6d8ceb714e
5
5
  SHA512:
6
- metadata.gz: 566ad106b83ae4838f08d0233f485b910e9f86d484e819c72034b4b9fb36422db9e490bcfc9f0d24add9e0f021d244400b4704644afc38bf508c90f7dff4408f
7
- data.tar.gz: 32b9ae7a7685e73e17b23fba501c8036ec04065c9ee46afc97f855fbd6fc2b6cfcf2da4c29df9e685760e27cb0024d08cee470dee46be9aaf099949e1a2a4ad5
6
+ metadata.gz: 4a90438bfd7b6edd9a91eb87e02be7a6206cd7476a4343de5998a8896578e0fafff3f8f5a5a97efdbf8ff1d8e98c5f4b23da77f5cc78318ca32737c17c93b288
7
+ data.tar.gz: 8b0e1c387bf140520b1919361aa2d6a753f2e21f4b09188c951d40186bd525a767603ae0c37d649b6e5e7243ae9c40276e53aba2c74e34d682cf6feeb3e4683b
data/README.md CHANGED
@@ -13,6 +13,15 @@ with **mruby**.
13
13
  executable using mruby. The .rb files must be
14
14
  [mruby-compatible](https://github.com/mruby/mruby/blob/master/doc/limitations.md) (roughly equivalent to MRI v1.9).
15
15
 
16
+ Two primary modes of operation are supported:
17
+
18
+ 1. ruby code is injected into a C wrapper which is then compiled. The ruby
19
+ code is **interpreted** every time the resulting binary is executed.
20
+
21
+ 2. ruby code is first interpreted into **bytecode**, and the bytecode
22
+ is injected into a C wrapper which is then compiled. This means a faster
23
+ runtime as the code interpretation is not performed at runtime.
24
+
16
25
  ## Install
17
26
 
18
27
  ### `git clone`
@@ -67,16 +76,24 @@ Prerequisites:
67
76
  gem install mruby_tools
68
77
  ```
69
78
 
70
- Now, `mrbt` may be used. It will need to know where to find the mruby_dir,
71
- so specify it with the `-m` flag or `MRUBY_DIR` environment variable.
79
+ Now, `mrbt` may be used. We set the `MRUBY_DIR` environment variable:
72
80
 
73
81
  ```shell
74
- export MRUBY_DIR=~/src/mruby-1.3.0 # or wherever
82
+ export MRUBY_DIR=~/src/mruby-1.3.0 # or wherever it lives
75
83
  mrbt file1.rb file2.rb # etc.
76
84
  ```
77
85
 
78
86
  ## Usage
79
87
 
88
+ ```
89
+ USAGE: mrbt file1.rb file2.rb ...
90
+ OPTIONS: -o outfile (provide a name for the standalone executable)
91
+ -c generated.c (leave the specified C file on the filesystem)
92
+ -m mruby_dir (provide the dir for mruby src)
93
+ -b (pregenerate ruby bytecode for faster execution)
94
+ -v (verbose)
95
+ ```
96
+
80
97
  With no additional options, `mrbt` will inject the contents of file1.rb and
81
98
  file2.rb into C strings, to be loaded with mrb_load_nstring(), written to a
82
99
  Tempfile. `mrbt` then compiles the generated .c file using GCC and writes
@@ -97,25 +114,12 @@ rake mrbt -- examples/hello_world.rb examples/goodbye_world.rb -o adios
97
114
 
98
115
  Other useful rake tasks:
99
116
 
100
- * hello world - compiles and runs `examples/hello_world.rb`
101
- * timed_simplex - compiles and runs several files that work together
117
+ * hello world - compiles and runs `examples/hello_world.rb`
118
+ * timed_simplex - compiles and runs several files that work together
102
119
  * raise_exception - compiles and runs `examples/raise.rb`
103
120
  * examples - runs hello_world and timed_simplex
104
- * verbose - add verbose output, e.g. `rake verbose hello_world`
105
-
106
- ### With *rubygems*
107
-
108
- ```shell
109
- mrbt -h
110
- ```
111
-
112
- ```
113
- USAGE: mrbt file1.rb file2.rb ...
114
- OPTIONS: -o outfile (provide a name for the standalone executable)
115
- -c generated.c (leave the specified C file on the filesystem)
116
- -m mruby_dir (provide the dir for mruby src)
117
- -v (verbose)
118
- ```
121
+ * verbose - add verbose output, e.g. `rake verbose hello_world`
122
+ * bytecode - enable bytecode generation at compile time
119
123
 
120
124
  ## Examples
121
125
 
@@ -162,7 +166,7 @@ rake verbose hello_world
162
166
  ```
163
167
 
164
168
  ```
165
- /home/vagrant/.rubies/ruby-2.4.0/bin/ruby -Ilib bin/mrbt examples/hello_world.rb -o examples/hello_world -v
169
+ /home/vagrant/.rubies/ruby-2.4.0/bin/ruby -Ilib bin/mrbt -v examples/hello_world.rb -o examples/hello_world
166
170
  #include <stdlib.h>
167
171
  #include <mruby.h>
168
172
  #include <mruby/compile.h>
@@ -198,21 +202,21 @@ main(void)
198
202
  return 0;
199
203
  }
200
204
 
201
- generated /tmp/mrbt-20171117-24568-no7ee3.c
205
+ generated /tmp/mrbt-20171122-20650-4pi6tt.c
202
206
  compiling...
203
207
  created binary executable: examples/hello_world
204
208
 
205
209
  file examples/hello_world
206
- examples/hello_world: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=2114ab60983156c92a5a74b88895f9c43a4bb086, not stripped
210
+ examples/hello_world: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=e9fb81e70686e761cf49202efc4f3e733d7aab17, not stripped
207
211
 
208
212
  stat examples/hello_world
209
213
  File: ‘examples/hello_world’
210
- Size: 1559056 Blocks: 3048 IO Block: 4096 regular file
211
- Device: 801h/2049d Inode: 388049 Links: 1
214
+ Size: 1631784 Blocks: 3192 IO Block: 4096 regular file
215
+ Device: 801h/2049d Inode: 388542 Links: 1
212
216
  Access: (0755/-rwxr-xr-x) Uid: ( 1000/ vagrant) Gid: ( 1000/ vagrant)
213
- Access: 2017-11-17 18:48:25.713629203 +0000
214
- Modify: 2017-11-17 18:48:25.709629203 +0000
215
- Change: 2017-11-17 18:48:25.709629203 +0000
217
+ Access: 2017-11-22 23:42:12.202875568 +0000
218
+ Modify: 2017-11-22 23:42:12.190881566 +0000
219
+ Change: 2017-11-22 23:42:12.190881566 +0000
216
220
  Birth: -
217
221
 
218
222
  examples/hello_world
@@ -224,3 +228,82 @@ This proceeds exactly as before but with additional output:
224
228
  * Show the generated C code
225
229
  * Note the temporary file containing the C code
226
230
  * Call `file` and `stat` on the output executable
231
+
232
+ ### Verbose Bytecode Hello World
233
+
234
+ ```shell
235
+ mrbt -v examples/hello_world.rb -b
236
+
237
+ # or
238
+ rake mrbt -- -b examples/hello_world.rb -v
239
+
240
+ # or even
241
+ rake verbose bytecode hello_world
242
+ ```
243
+
244
+ ```
245
+ /home/vagrant/.rubies/ruby-2.4.0/bin/ruby -Ilib bin/mrbt -b -v examples/hello_world.rb -o examples/hello_world
246
+ creating bytecode.mrb...
247
+ #include <stdlib.h>
248
+ #include <stdint.h>
249
+ #include <mruby.h>
250
+ #include <mruby/string.h>
251
+ #include <mruby/irep.h>
252
+
253
+ const uint8_t
254
+ #if defined __GNUC__
255
+ __attribute__((aligned(4)))
256
+ #elif defined _MSC_VER
257
+ __declspec(align(4))
258
+ #endif
259
+ /* bytecode.mrb */
260
+ test_symbol[] = {
261
+ 0x52,0x49,0x54,0x45,0x30,0x30,0x30,0x34,0x22,0x80,0x00,0x00,0x00,0x65,0x4d,0x41,0x54,0x5a,0x30,0x30,0x30,0x30,0x49,0x52,0x45,0x50,0x00,0x00,0x00,0x47,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x3f,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x80,0x00,0x06,0x01,0x00,0x00,0x84,0x00,0x80,0x00,0xa0,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x04,0x70,0x75,0x74,0x73,0x00,0x00,0x0b,0x68,0x65,0x6c,0x6c,0x6f,0x5f,0x77,0x6f,0x72,0x6c,0x64,0x00,0x45,0x4e,0x44,0x00,0x00,0x00,0x00,0x08,
262
+ };
263
+
264
+ void check_exc(mrb_state *mrb) {
265
+ if (mrb->exc) {
266
+ mrb_value exc = mrb_obj_value(mrb->exc);
267
+ mrb_value exc_msg = mrb_funcall(mrb, exc, "to_s", 0);
268
+ fprintf(stderr, "ERROR %s: %s\n",
269
+ mrb_obj_classname(mrb, exc),
270
+ mrb_str_to_cstr(mrb, exc_msg));
271
+ /* mrb_print_backtrace(mrb); # empty */
272
+ exit(1);
273
+ }
274
+ }
275
+
276
+ int
277
+ main(void)
278
+ {
279
+ mrb_state *mrb = mrb_open();
280
+ if (!mrb) {
281
+ printf("mrb problem");
282
+ exit(1);
283
+ }
284
+ mrb_load_irep(mrb, test_symbol);
285
+ check_exc(mrb);
286
+ mrb_close(mrb);
287
+ return 0;
288
+ }
289
+
290
+ generated /tmp/mrbt-20171122-25456-azsw3n.c
291
+ compiling...
292
+ created binary executable: examples/hello_world
293
+
294
+ file examples/hello_world
295
+ examples/hello_world: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=61e903e56a9e5d1159cb5a5ea4a669b05b493f44, not stripped
296
+
297
+ stat examples/hello_world
298
+ File: ‘examples/hello_world’
299
+ Size: 1324616 Blocks: 2592 IO Block: 4096 regular file
300
+ Device: 801h/2049d Inode: 388542 Links: 1
301
+ Access: (0755/-rwxr-xr-x) Uid: ( 1000/ vagrant) Gid: ( 1000/ vagrant)
302
+ Access: 2017-11-22 23:46:09.540147567 +0000
303
+ Modify: 2017-11-22 23:46:09.536149567 +0000
304
+ Change: 2017-11-22 23:46:09.536149567 +0000
305
+ Birth: -
306
+
307
+ examples/hello_world
308
+ hello_world
309
+ ```
data/Rakefile CHANGED
@@ -37,8 +37,15 @@ task :verbose do
37
37
  @verbose = true
38
38
  end
39
39
 
40
+ @bytecode = false
41
+
42
+ task :bytecode do
43
+ @bytecode = true
44
+ end
45
+
40
46
  def mrbt *args
41
47
  args.unshift('-v') if @verbose and !args.include?('-v')
48
+ args.unshift('-b') if @bytecode and !args.include?('-b')
42
49
  ruby '-Ilib', 'bin/mrbt', *args
43
50
  end
44
51
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3.1
1
+ 0.0.4.1
data/bin/mrbt CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'tempfile'
4
3
  require 'mruby_tools'
5
4
 
6
5
  # args like: file1.rb file2.rb -o outfile
@@ -9,18 +8,35 @@ require 'mruby_tools'
9
8
  opts = MRubyTools::CLI.args(ARGV)
10
9
  MRubyTools::CLI.usage if opts[:help]
11
10
 
11
+ FAIL_MRUBY_NOT_FOUND = 1
12
+ FAIL_MRBC_BYTECODE = 1
13
+ FAIL_GCC = 1
14
+
15
+
12
16
  mrb = MRubyTools.new(opts[:mruby_dir]) # nil is fine
13
17
  begin
14
18
  mrb.validate!
15
19
  rescue MRubyTools::MRubyNotFound => e
16
20
  warn "#{e.class}: can't find #{e}"
17
- exit 1
21
+ exit FAIL_MRUBY_NOT_FOUND
18
22
  end
19
23
 
20
24
  rb_files = opts.fetch(:rb_files)
21
25
  MRubyTools::CLI.usage("no .rb files provided") if rb_files.empty?
22
26
 
23
- c_code = MRubyTools::C.wrapper(rb_files)
27
+ # inject a string vs create and inject bytecode
28
+ if opts[:bytecode]
29
+ bc_file = 'bytecode.mrb'
30
+ puts "creating #{bc_file}..."
31
+ if mrb.mrbc rb_files, bc_file
32
+ c_code = MRubyTools::C.bytecode_wrapper(bc_file)
33
+ else
34
+ warn "FATAL: mrbc bytecode generation failed"
35
+ exit FAIL_MRBC_BYTECODE
36
+ end
37
+ else
38
+ c_code = MRubyTools::C.wrapper(rb_files)
39
+ end
24
40
  puts c_code + "\n" if opts[:verbose]
25
41
 
26
42
  c_file = opts.fetch(:c_file)
@@ -34,5 +50,5 @@ if mrb.compile(c_file.path, out_file)
34
50
  puts "created binary executable: #{out_file}"
35
51
  else
36
52
  warn "FATAL: compile failed"
37
- exit 1
53
+ exit FAIL_GCC
38
54
  end
@@ -9,12 +9,13 @@ class MRubyTools
9
9
  ENV['MRUBY_DIR'] || MRUBY_DIR
10
10
  end
11
11
 
12
- attr_accessor :mruby_dir, :inc_path, :ar_path
12
+ attr_accessor :mruby_dir, :inc_path, :ar_path, :bin_path
13
13
 
14
14
  def initialize(mruby_dir = nil)
15
15
  @mruby_dir = mruby_dir || self.class.mruby_dir
16
16
  @inc_path = File.join(@mruby_dir, 'include')
17
17
  @ar_path = File.join(@mruby_dir, 'build', 'host', 'lib', 'libmruby.a')
18
+ @bin_path = File.join(@mruby_dir, 'bin')
18
19
  end
19
20
 
20
21
  def src?
@@ -28,6 +29,7 @@ class MRubyTools
28
29
  def validate!
29
30
  raise(MRubyNotFound, @inc_path) unless File.directory? @inc_path
30
31
  raise(MRubyNotFound, @ar_path) unless File.readable? @ar_path
32
+ raise(MRubyNotFound, @bin_path) unless File.directory? @bin_path
31
33
  self
32
34
  end
33
35
 
@@ -39,7 +41,80 @@ class MRubyTools
39
41
  system('gcc', *self.gcc_args(c_file, out_file))
40
42
  end
41
43
 
44
+ # interpret several rb_files into a binary out_file contaning bytecode
45
+ def mrbc(rb_files, out_file)
46
+ system(File.join(@bin_path, 'mrbc'), '-o', out_file, *rb_files)
47
+ end
48
+
42
49
  module C
50
+ def self.slurp_mrb(bc_file, indent: ' ')
51
+ test_symbol = File.read(bc_file).each_byte.reduce('') { |memo, b|
52
+ memo + format("0x%0.2x,", b.ord)
53
+ }
54
+ ["/* #{bc_file} */",
55
+ "test_symbol[] = {",
56
+ test_symbol,
57
+ "};",
58
+ ].map { |s| indent + s }.join("\n")
59
+ end
60
+
61
+ def self.slurp_rb(rb_filename, indent: ' ')
62
+ c_str = File.read(rb_filename)
63
+ size = c_str.size
64
+ c_str = c_str.gsub("\n", '\n').gsub('"', '\"')
65
+ [ "/* #{rb_filename} */",
66
+ 'mrb_load_nstring(mrb, "' + c_str + '", ' + "#{size});",
67
+ "check_exc(mrb, \"#{rb_filename}\");",
68
+ ].map { |s| indent + s }.join("\n")
69
+ end
70
+
71
+ def self.bytecode_wrapper(bc_file)
72
+ c_code = <<'EOF'
73
+ #include <stdlib.h>
74
+ #include <stdint.h>
75
+ #include <mruby.h>
76
+ #include <mruby/string.h>
77
+ #include <mruby/irep.h>
78
+
79
+ const uint8_t
80
+ #if defined __GNUC__
81
+ __attribute__((aligned(4)))
82
+ #elif defined _MSC_VER
83
+ __declspec(align(4))
84
+ #endif
85
+ EOF
86
+ c_code += slurp_mrb(bc_file, indent: '') + "\n\n"
87
+
88
+ c_code += <<'EOF'
89
+ void check_exc(mrb_state *mrb) {
90
+ if (mrb->exc) {
91
+ mrb_value exc = mrb_obj_value(mrb->exc);
92
+ mrb_value exc_msg = mrb_funcall(mrb, exc, "to_s", 0);
93
+ fprintf(stderr, "ERROR %s: %s\n",
94
+ mrb_obj_classname(mrb, exc),
95
+ mrb_str_to_cstr(mrb, exc_msg));
96
+ /* mrb_print_backtrace(mrb); # empty */
97
+ exit(1);
98
+ }
99
+ }
100
+
101
+ int
102
+ main(void)
103
+ {
104
+ mrb_state *mrb = mrb_open();
105
+ if (!mrb) {
106
+ printf("mrb problem");
107
+ exit(1);
108
+ }
109
+ mrb_load_irep(mrb, test_symbol);
110
+ check_exc(mrb);
111
+ mrb_close(mrb);
112
+ return 0;
113
+ }
114
+ EOF
115
+ c_code
116
+ end
117
+
43
118
  def self.wrapper(rb_files)
44
119
  c_code = <<'EOF'
45
120
  #include <stdlib.h>
@@ -80,29 +155,22 @@ EOF
80
155
  EOF
81
156
  c_code
82
157
  end
83
-
84
- def self.slurp_rb(rb_filename, indent: ' ')
85
- c_str = File.read(rb_filename)
86
- size = c_str.size
87
- c_str = c_str.gsub("\n", '\n').gsub('"', '\"')
88
- [ "/* #{rb_filename} */",
89
- 'mrb_load_nstring(mrb, "' + c_str + '", ' + "#{size});",
90
- "check_exc(mrb, \"#{rb_filename}\");",
91
- ].map { |s| indent + s }.join("\n")
92
- end
93
158
  end
94
159
 
95
160
  module CLI
161
+ USAGE_EXIT = 1
162
+
96
163
  def self.usage(msg = nil)
97
164
  puts <<EOF
98
165
  USAGE: mrbt file1.rb file2.rb ...
99
166
  OPTIONS: -o outfile (provide a name for the standalone executable)
100
167
  -c generated.c (leave the specified C file on the filesystem)
101
168
  -m mruby_dir (provide the dir for mruby src)
169
+ -b (pregenerate ruby bytecode for faster execution)
102
170
  -v (verbose)
103
171
  EOF
104
172
  warn " ERROR: #{msg}" if msg
105
- exit(msg ? 1 : 0)
173
+ exit(msg ? USAGE_EXIT : 0)
106
174
  end
107
175
 
108
176
  def self.args(argv = ARGV)
@@ -112,6 +180,7 @@ EOF
112
180
  mruby_dir = nil
113
181
  verbose = false
114
182
  help = false
183
+ bytecode = false
115
184
 
116
185
  while !argv.empty?
117
186
  arg = argv.shift
@@ -128,19 +197,23 @@ EOF
128
197
  elsif arg == '-m'
129
198
  mruby_dir = argv.shift
130
199
  raise "no mruby_dir provided with -m" unless mruby_dir
200
+ elsif arg == '-b'
201
+ bytecode = true
131
202
  else
132
- rb_files << arg
203
+ rb_files << arg unless arg == '--'
133
204
  end
134
205
  end
135
206
 
136
207
  c_file ||= Tempfile.new(['mrbt-', '.c'])
208
+ out_file ||= 'outfile'
137
209
 
138
210
  { verbose: verbose,
139
211
  help: help,
140
212
  c_file: c_file,
141
- out_file: out_file || 'outfile',
213
+ out_file: out_file,
142
214
  rb_files: rb_files,
143
- mruby_dir: mruby_dir }
215
+ mruby_dir: mruby_dir,
216
+ bytecode: bytecode }
144
217
  end
145
218
  end
146
219
  end
@@ -18,9 +18,11 @@ describe MRubyTools do
18
18
  obj.mruby_dir.must_be_kind_of String
19
19
  obj.inc_path.must_be_kind_of String
20
20
  obj.ar_path.must_be_kind_of String
21
+ obj.bin_path.must_be_kind_of String
21
22
  }
22
23
  @valid.inc_path.must_match %r{include}
23
24
  @valid.ar_path.must_match %r{libmruby.a}
25
+ @valid.bin_path.must_match %r{bin}
24
26
  end
25
27
  end
26
28
 
@@ -29,8 +31,19 @@ describe MRubyTools do
29
31
  str = MRubyTools::C.slurp_rb(__FILE__)
30
32
  str.must_be_kind_of String
31
33
  str.wont_be_empty
32
- str.must_match(/mrb_load_n?string\(/)
33
- str.must_match(/exc/)
34
+ str.must_match %r{mrb_load_n?string\(}
35
+ str.must_match %r{exc}
36
+ end
37
+ end
38
+
39
+ describe "C.slurp_mrb" do
40
+ it "must inject the contents of a bytecode file into test_symbol[]" do
41
+ # bytecode is pure binary -- it doesn't matter what file we provide
42
+ str = MRubyTools::C.slurp_mrb(__FILE__)
43
+ str.must_be_kind_of String
44
+ str.wont_be_empty
45
+ str.must_match %r{test_symbol}
46
+ str.must_match %r{0x\d\d,}
34
47
  end
35
48
  end
36
49
 
@@ -40,15 +53,28 @@ describe MRubyTools do
40
53
  str = MRubyTools::C.wrapper(rb_files)
41
54
  str.must_be_kind_of String
42
55
  str.wont_be_empty
43
- str.must_match(/main\(void\)/)
44
- str.must_match(/return/)
45
- str.must_match(/exit/)
46
- str.must_match(/mruby/)
47
- str.must_match(/mrb/)
56
+ str.must_match %r{main\(void\)}
57
+ str.must_match %r{return}
58
+ str.must_match %r{exit}
59
+ str.must_match %r{mruby}
60
+ str.must_match %r{mrb}
48
61
  }
49
62
  end
50
63
  end
51
64
 
65
+ describe "C.bytecode_wrapper" do
66
+ it "must return a string of mruby C code" do
67
+ str = MRubyTools::C.bytecode_wrapper(__FILE__)
68
+ str.must_be_kind_of String
69
+ str.wont_be_empty
70
+ str.must_match %r{main\(void\)}
71
+ str.must_match %r{return}
72
+ str.must_match %r{exit}
73
+ str.must_match %r{mruby}
74
+ str.must_match %r{mrb}
75
+ end
76
+ end
77
+
52
78
  describe "CLI.args" do
53
79
  it "must provide a hash with expected keys" do
54
80
  h = MRubyTools::CLI.args([])
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mruby_tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3.1
4
+ version: 0.0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Hull
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-22 00:00:00.000000000 Z
11
+ date: 2017-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake