h8 0.4.5 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/h8/h8.h +1 -2
- data/ext/h8/main.cpp +2 -2
- data/ext/h8/ruby_gate.cpp +1 -1
- data/hybrid8.gemspec +1 -0
- data/lib/h8.rb +3 -0
- data/lib/h8/coffee.rb +3 -4
- data/lib/h8/context.rb +51 -11
- data/lib/h8/value.rb +33 -0
- data/lib/h8/version.rb +1 -1
- data/lib/scripts/globals.coffee +2 -1
- data/spec/coffee_spec.rb +39 -5
- data/spec/ruby_gate_spec.rb +47 -21
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae98780cc495a9c2f15db1b3de81f81cc014978b
|
4
|
+
data.tar.gz: ee00bd70c38b2f4b62ecf8beddb2e15fb6aacb61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a2be9806423de66eacb312891d1abcff2af0f24679e740af339689cae1ae50fd8dbb07d15d138fc13976bbb410b3acf92951d020bcb96df93c16ab9a5fd3b20
|
7
|
+
data.tar.gz: 85f4398e82fc5a818654936cdb2b0fe5b51ee64c8e08284d131657d4f89c90b55585fbb8fc052dfe673a8371ce9ad7f69ab4a440c3d8301ec5a23d5777981250
|
data/ext/h8/h8.h
CHANGED
@@ -19,8 +19,7 @@ extern VALUE value_class;
|
|
19
19
|
extern VALUE ruby_gate_class;
|
20
20
|
extern VALUE Rundefined;
|
21
21
|
|
22
|
-
extern ID id_is_a;
|
23
|
-
extern ID id_safe_call;
|
22
|
+
extern ID id_is_a, id_safe_call, id_safe_proc_call;
|
24
23
|
|
25
24
|
VALUE protect_ruby(const std::function<VALUE()> &block);
|
26
25
|
|
data/ext/h8/main.cpp
CHANGED
@@ -14,8 +14,7 @@ VALUE ruby_gate_class;
|
|
14
14
|
VALUE value_class;
|
15
15
|
VALUE Rundefined;
|
16
16
|
|
17
|
-
ID id_is_a;
|
18
|
-
ID id_safe_call;
|
17
|
+
ID id_is_a, id_safe_call, id_safe_proc_call;
|
19
18
|
|
20
19
|
VALUE protect_ruby(const std::function<VALUE()> &block) {
|
21
20
|
try {
|
@@ -189,6 +188,7 @@ void Init_h8(void) {
|
|
189
188
|
|
190
189
|
id_is_a = rb_intern("is_a?");
|
191
190
|
id_safe_call = rb_intern("secure_call");
|
191
|
+
id_safe_proc_call = rb_intern("safe_proc_call");
|
192
192
|
|
193
193
|
VALUE h8 = rb_define_module("H8");
|
194
194
|
|
data/ext/h8/ruby_gate.cpp
CHANGED
@@ -124,7 +124,7 @@ VALUE h8::RubyGate::rescue_callback(VALUE me, VALUE exception_object) {
|
|
124
124
|
VALUE RubyGate::call(VALUE args) {
|
125
125
|
VALUE callable = rb_ary_pop(args);
|
126
126
|
VALUE context = rb_ary_pop(args);
|
127
|
-
VALUE res = rb_funcall(context,
|
127
|
+
VALUE res = rb_funcall(context, id_safe_proc_call, 2, callable, args);
|
128
128
|
return res;
|
129
129
|
}
|
130
130
|
|
data/hybrid8.gemspec
CHANGED
@@ -33,6 +33,7 @@ spec = Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_development_dependency "rake"
|
34
34
|
spec.add_development_dependency "rake-compiler"
|
35
35
|
spec.add_development_dependency "rspec", '~> 3.1'
|
36
|
+
spec.add_development_dependency 'hashie', '>= 0.1.2'
|
36
37
|
|
37
38
|
spec.add_dependency 'pargser', '>= 0.1.2'
|
38
39
|
end
|
data/lib/h8.rb
CHANGED
data/lib/h8/coffee.rb
CHANGED
@@ -18,7 +18,7 @@ module H8
|
|
18
18
|
# compiler instance across all threads with a mutex.
|
19
19
|
def self.eval src, ** kwargs
|
20
20
|
@@mutex.synchronize {
|
21
|
-
(@@compiler ||= Coffee.new).eval src, **
|
21
|
+
(@@compiler ||= Coffee.new).eval src, **kwargs
|
22
22
|
}
|
23
23
|
end
|
24
24
|
|
@@ -29,13 +29,13 @@ module H8
|
|
29
29
|
# compiler instance across all threads with a mutex.
|
30
30
|
def self.compile src, ** kwargs
|
31
31
|
@@mutex.synchronize {
|
32
|
-
(@@compiler ||= Coffee.new).compile src, **
|
32
|
+
(@@compiler ||= Coffee.new).compile src, **kwargs
|
33
33
|
}
|
34
34
|
end
|
35
35
|
|
36
36
|
# Create compiler instance.
|
37
37
|
def initialize
|
38
|
-
@context = H8::Context.new
|
38
|
+
@context = H8::Context.new noglobals: true
|
39
39
|
@context.eval read_script 'coffee-script.js'
|
40
40
|
eval read_script('globals.coffee')
|
41
41
|
end
|
@@ -70,5 +70,4 @@ module H8
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
73
|
end
|
data/lib/h8/context.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require 'thread'
|
2
|
+
require 'h8'
|
2
3
|
|
3
4
|
module H8
|
5
|
+
|
4
6
|
class Context
|
5
7
|
# Create new context optionally providing variables hash
|
6
|
-
def initialize **kwargs
|
8
|
+
def initialize noglobals: false, **kwargs
|
7
9
|
@idcount = 0
|
8
10
|
set_all **kwargs
|
9
11
|
_set_var '___create_ruby_class', -> (cls, args) {
|
10
12
|
_do_create_ruby_class cls, args
|
11
13
|
}
|
14
|
+
# noglobals or execute_script 'globals.coffee'
|
12
15
|
end
|
13
16
|
|
14
17
|
# set variables from keyword arguments to this context
|
@@ -48,13 +51,13 @@ module H8
|
|
48
51
|
# If you need to execute same script more than once consider first H8::Coffee.compile
|
49
52
|
# and cache compiled script.
|
50
53
|
def coffee script, ** kwargs
|
51
|
-
eval Coffee.compile script, **kwargs
|
54
|
+
eval Coffee.compile script, ** kwargs
|
52
55
|
end
|
53
56
|
|
54
57
|
|
55
58
|
# Execute script in a new context with optionally set vars. @see H8#set_all
|
56
59
|
# @return [Value] wrapped object returned by the script
|
57
|
-
def self.eval script, file_name: nil, **kwargs
|
60
|
+
def self.eval script, file_name: nil, ** kwargs
|
58
61
|
Context.new(** kwargs).eval script, file_name: file_name
|
59
62
|
end
|
60
63
|
|
@@ -67,12 +70,12 @@ module H8
|
|
67
70
|
def self.secure_call instance, method, args=nil
|
68
71
|
method = method.to_sym
|
69
72
|
begin
|
70
|
-
m
|
73
|
+
m = instance.public_method(method)
|
71
74
|
owner = m.owner
|
72
75
|
if can_access?(owner)
|
73
76
|
return m.call(*args) if method[0] == '[' || method[-1] == '='
|
74
77
|
if m.arity != 0
|
75
|
-
return -> (*args) { m.call *args }
|
78
|
+
return ProcGate.new( -> (*args) { m.call *args } )
|
76
79
|
else
|
77
80
|
return m.call
|
78
81
|
end
|
@@ -80,7 +83,7 @@ module H8
|
|
80
83
|
rescue NameError
|
81
84
|
# No exact method, calling []/[]= if any
|
82
85
|
method, args = if method[-1] == '='
|
83
|
-
[:[]=, [method[0..-2].to_s, args[0]]
|
86
|
+
[:[]=, [method[0..-2].to_s, args[0]]]
|
84
87
|
else
|
85
88
|
[:[], [method.to_s]]
|
86
89
|
end
|
@@ -88,7 +91,11 @@ module H8
|
|
88
91
|
m = instance.public_method(method)
|
89
92
|
if can_access?(owner)
|
90
93
|
if method == :[]
|
91
|
-
|
94
|
+
if instance.is_a?(Hash)
|
95
|
+
return m.call(*args) || m.call(args[0].to_sym)
|
96
|
+
else
|
97
|
+
return m.call(*args)
|
98
|
+
end
|
92
99
|
else
|
93
100
|
return m.call(*args)
|
94
101
|
end
|
@@ -115,10 +122,13 @@ module H8
|
|
115
122
|
# Set var that could be either a callable, class instance, simple value or a Class class
|
116
123
|
# in which case constructor function will be created
|
117
124
|
def set_var name, value
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
125
|
+
case value
|
126
|
+
when Class
|
127
|
+
_gate_class name.to_s, -> (*args) { value.new *args }
|
128
|
+
when Proc
|
129
|
+
_set_var name, ProcGate.new(value)
|
130
|
+
else
|
131
|
+
_set_var name, value
|
122
132
|
end
|
123
133
|
end
|
124
134
|
|
@@ -127,6 +137,36 @@ module H8
|
|
127
137
|
def _do_create_ruby_class(klass, arguments)
|
128
138
|
klass.new *H8::arguments_to_a(arguments.to_ruby.values)
|
129
139
|
end
|
140
|
+
|
141
|
+
|
142
|
+
@@base = File.expand_path File.join(File.dirname(__FILE__), '../scripts')
|
143
|
+
@@cache = {}
|
144
|
+
|
145
|
+
def execute_script name
|
146
|
+
p [:exs, name]
|
147
|
+
script = @@cache[name] ||= begin
|
148
|
+
p 'cache miss'
|
149
|
+
script = open(File.join(@@base, name), 'r').read
|
150
|
+
name.downcase.end_with?('.coffee') ? H8::Coffee.compile(script) : script
|
151
|
+
end
|
152
|
+
eval script
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
# The gate for Ruby's callable to support javascript's 'apply' functionality
|
158
|
+
class ProcGate
|
159
|
+
def initialize callable
|
160
|
+
@callable = callable
|
161
|
+
end
|
162
|
+
|
163
|
+
def apply this, args
|
164
|
+
@callable.call *args
|
165
|
+
end
|
166
|
+
|
167
|
+
def call *args
|
168
|
+
@callable.call *args
|
169
|
+
end
|
130
170
|
end
|
131
171
|
|
132
172
|
end
|
data/lib/h8/value.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
1
3
|
module H8
|
2
4
|
|
3
5
|
# Wrapper for javascript objects.
|
@@ -179,6 +181,37 @@ module H8
|
|
179
181
|
|
180
182
|
end
|
181
183
|
|
184
|
+
class OpenStruct
|
185
|
+
# OpenStruct converts to plain ruby hash in depth. Primary usage
|
186
|
+
# is when it was used bu javascript and could contain gated objects.
|
187
|
+
def to_ruby depth=0
|
188
|
+
to_h.to_ruby depth+1
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class Hash
|
193
|
+
# Hash copies in depth converting its data. Primary usage
|
194
|
+
# is when it was used bu javascript and could contain gated objects.
|
195
|
+
#
|
196
|
+
# Important! that converted keys are turned to string even of were
|
197
|
+
# pure ruby symbols. This is done to remove ambiguity: work the same
|
198
|
+
# with ruby hashes, javasctipt objects, OpenStruct and Hashie::Mash instances
|
199
|
+
def to_ruby depth=0
|
200
|
+
res = {}
|
201
|
+
depth += 1
|
202
|
+
each { |k,v| res[k.to_ruby(depth).to_s] = v.to_ruby depth }
|
203
|
+
res
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class Array
|
208
|
+
# @return new array with all components converted to_ruby
|
209
|
+
def to_ruby depth
|
210
|
+
depth += 1
|
211
|
+
map { |x| x.to_ruby depth }
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
182
215
|
# Ruby object's t_ruby does nothing (tree conversion optimization)
|
183
216
|
class Object
|
184
217
|
# It is already a ruby object. Gate objects should override
|
data/lib/h8/version.rb
CHANGED
data/lib/scripts/globals.coffee
CHANGED
data/spec/coffee_spec.rb
CHANGED
@@ -35,7 +35,7 @@ describe 'coffeescript' do
|
|
35
35
|
# above is bad
|
36
36
|
END
|
37
37
|
# pending
|
38
|
-
expect(->{
|
38
|
+
expect(-> {
|
39
39
|
H8::Coffee.compile script, file_name: 'test.coffee'
|
40
40
|
}).to raise_error(H8::JsError) { |e| e.to_s.should =~ /test.coffee\:4/ }
|
41
41
|
end
|
@@ -63,15 +63,49 @@ describe 'coffeescript' do
|
|
63
63
|
// CoffeeScript.sourceMaps['inner'] = res.sourceMap
|
64
64
|
eval(res.js);
|
65
65
|
END
|
66
|
-
cxt
|
66
|
+
cxt = H8::Coffee.new.context
|
67
67
|
cxt[:puts] = -> (*args) { puts args.join(' ') }
|
68
|
-
cxt[:src]
|
68
|
+
cxt[:src] = src
|
69
69
|
# cxt[:src] = 'return "hello"'
|
70
70
|
begin
|
71
|
-
|
72
|
-
rescue Exception=>e
|
71
|
+
res = cxt.eval script, file_name: 'extest.coffee'
|
72
|
+
rescue Exception => e
|
73
73
|
puts e
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
context 'realword' do
|
78
|
+
class Room
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should process varargs' do
|
82
|
+
c = H8::Context.new
|
83
|
+
c[:puts] = ->(*args) { puts "> "+args.join('') }
|
84
|
+
c.coffee <<-End
|
85
|
+
@.fn1 = (args...) ->
|
86
|
+
args.join(',')
|
87
|
+
|
88
|
+
@.test = (args...) ->
|
89
|
+
fn1 'first', args...
|
90
|
+
End
|
91
|
+
c.coffee('return test(1,2,3);').should == 'first,1,2,3'
|
92
|
+
|
93
|
+
# Real world example
|
94
|
+
c[:r3] = -> (*args) {
|
95
|
+
@last_args = args
|
96
|
+
}
|
97
|
+
c[:r4] = -> (first, second=0) {
|
98
|
+
[first+100, second]
|
99
|
+
}
|
100
|
+
script = <<-End
|
101
|
+
@r1 = (args...) ->
|
102
|
+
r3 'done', args[0..-2]...
|
103
|
+
@r2 = (args...) ->
|
104
|
+
r4 args...
|
105
|
+
End
|
106
|
+
c.coffee script
|
107
|
+
c.eval('r1( "now", 1, 2, 4);').should == ['done', 'now', 1, 2]
|
108
|
+
c.eval('r2( 100, 200);').should == [200, 200]
|
109
|
+
end
|
110
|
+
end
|
77
111
|
end
|
data/spec/ruby_gate_spec.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'h8'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'hashie'
|
3
5
|
|
4
6
|
describe 'ruby gate' do
|
5
7
|
|
@@ -173,7 +175,7 @@ describe 'ruby gate' do
|
|
173
175
|
end
|
174
176
|
|
175
177
|
class Test < Base
|
176
|
-
attr :ro
|
178
|
+
attr :ro, :val
|
177
179
|
attr_accessor :rw
|
178
180
|
|
179
181
|
def initialize
|
@@ -216,7 +218,7 @@ describe 'ruby gate' do
|
|
216
218
|
end
|
217
219
|
|
218
220
|
it 'should access object properties and methods' do
|
219
|
-
cxt
|
221
|
+
cxt = H8::Context.new
|
220
222
|
cxt.eval('RubyGate.prototype.test2 = function() { return "ttt"; }; null;');
|
221
223
|
cxt[:foo] = Test.new
|
222
224
|
cxt.eval('foo.ro').should == 'readonly'
|
@@ -231,19 +233,11 @@ describe 'ruby gate' do
|
|
231
233
|
cxt.eval('foo.object_id').should == H8::Undefined
|
232
234
|
cxt.eval('foo.prot_method').should == H8::Undefined
|
233
235
|
cxt.eval('foo.priv_method').should == H8::Undefined
|
234
|
-
cxt.eval('foo.test_args').should be_kind_of(
|
236
|
+
cxt.eval('foo.test_args').should be_kind_of(H8::ProcGate)
|
235
237
|
cxt.eval('foo.test_args("hi", "you")').should == 'hi-you'
|
236
238
|
cxt.eval('foo instanceof RubyGate').should == true
|
237
239
|
end
|
238
240
|
|
239
|
-
it 'should set ruby properties' do
|
240
|
-
cxt = H8::Context.new
|
241
|
-
cxt[:foo] = t = Test.new
|
242
|
-
cxt.eval('foo.rw="hello";')
|
243
|
-
t.rw.should == 'hello'
|
244
|
-
cxt.eval('foo.rw').should == 'hello'
|
245
|
-
end
|
246
|
-
|
247
241
|
context 'do interceptors' do
|
248
242
|
class Test2 < Base
|
249
243
|
attr :ro
|
@@ -280,7 +274,7 @@ describe 'ruby gate' do
|
|
280
274
|
cxt.eval('foo.send').should == H8::Undefined
|
281
275
|
cxt.eval('foo.prot_method').should == H8::Undefined
|
282
276
|
cxt.eval('foo.priv_method').should == H8::Undefined
|
283
|
-
cxt.eval('foo.test_args').should be_kind_of(
|
277
|
+
cxt.eval('foo.test_args').should be_kind_of(H8::ProcGate)
|
284
278
|
cxt.eval('foo.test_args("hi", "you")').should == 'hi-you'
|
285
279
|
end
|
286
280
|
|
@@ -294,15 +288,37 @@ describe 'ruby gate' do
|
|
294
288
|
end
|
295
289
|
|
296
290
|
it 'should add and intercept property access' do
|
297
|
-
# pending
|
298
291
|
t = Test.new
|
299
292
|
t.do_throw = true
|
300
293
|
cxt = H8::Context.new t: t
|
294
|
+
|
295
|
+
# see Test class implementation: this is a valid test
|
301
296
|
cxt.eval("t['foo'];").should == 'init[]'
|
297
|
+
cxt.eval("t.foo").should == 'init[]'
|
302
298
|
expect(-> { cxt.eval("t['foo1'];") }).to raise_error(RuntimeError)
|
303
|
-
cxt.eval("t
|
304
|
-
|
305
|
-
|
299
|
+
cxt.eval("t.foo='bar'");
|
300
|
+
cxt.eval("t.foo;").should == 'bar'
|
301
|
+
t.val.should == 'bar'
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'should allow adding data to ruby hash' do
|
305
|
+
[OpenStruct.new, Hashie::Mash.new].each { |s|
|
306
|
+
s.test = 'foo'
|
307
|
+
c = H8::Context.new
|
308
|
+
c[:data] = s
|
309
|
+
c[:assert] = -> (cond) { !cond and raise "assertion failed" }
|
310
|
+
c.coffee 'assert data.test == "foo"'
|
311
|
+
c.coffee 'data.test = "bar"; assert data.test == "bar"'
|
312
|
+
s.test.should == 'bar'
|
313
|
+
c.coffee 'data.foo = "baz"'
|
314
|
+
s.foo.should == 'baz'
|
315
|
+
c.coffee 'data.h = { foo: "bar", bar: { baz: 1 } }'
|
316
|
+
s.h.foo.should == 'bar'
|
317
|
+
c.coffee 'data.h.bar.baz == 1'
|
318
|
+
s.h.bar.baz.should == 1
|
319
|
+
c.coffee 'data.h.bar.arr = ["hello", { one: 2 }]'
|
320
|
+
s.to_ruby.should == { 'test' => "bar", 'foo' => "baz", 'h' => { "foo" => "bar", "bar" => { "baz" => 1, "arr" => ["hello", { "one" => 2 }] } } }
|
321
|
+
}
|
306
322
|
end
|
307
323
|
|
308
324
|
it 'should access plain arrays (provide numeric indexes)' do
|
@@ -341,9 +357,9 @@ describe 'ruby gate' do
|
|
341
357
|
end
|
342
358
|
|
343
359
|
it 'should gate classes through API' do
|
344
|
-
c
|
360
|
+
c = H8::Context.new
|
345
361
|
la = -> (*args) {
|
346
|
-
{ 'hello' => 'world'}
|
362
|
+
{ 'hello' => 'world' }
|
347
363
|
}
|
348
364
|
c._gate_class 'Tec', la
|
349
365
|
c.eval("var res = new Tec()")
|
@@ -372,6 +388,10 @@ describe 'ruby gate' do
|
|
372
388
|
self
|
373
389
|
end
|
374
390
|
|
391
|
+
def testm a1, a2='???'
|
392
|
+
"#{a1} - #{a2}"
|
393
|
+
end
|
394
|
+
|
375
395
|
def to_str
|
376
396
|
inspect
|
377
397
|
end
|
@@ -391,18 +411,24 @@ describe 'ruby gate' do
|
|
391
411
|
cxt.eval('rc.init_args').should == ['hello', 'world']
|
392
412
|
end
|
393
413
|
|
414
|
+
it 'should provide apply to gated class and instance' do
|
415
|
+
c = H8::Context.new RClass: Gated
|
416
|
+
c.eval('new RClass().testm(1,"d");').should == '1 - d'
|
417
|
+
c.eval('new RClass().testm.apply( null, [1,"n"]);').should == '1 - n'
|
418
|
+
end
|
419
|
+
|
394
420
|
it 'should not die on calling wrong arity' do
|
395
421
|
cxt = H8::Context.new RClass: Gated
|
396
|
-
g1
|
422
|
+
g1 = cxt.eval 'var g1 = new RClass(1,2.3); g1'
|
397
423
|
|
398
424
|
# We call gated ruby object with wrong number of args
|
399
425
|
# which in turn causes attempt to call not callable result:
|
400
|
-
expect(-> {cxt.eval('g1.checkself(12)')}).to raise_error(NoMethodError)
|
426
|
+
expect(-> { cxt.eval('g1.checkself(12)') }).to raise_error(NoMethodError)
|
401
427
|
end
|
402
428
|
|
403
429
|
it 'should return self from gated class' do
|
404
430
|
cxt = H8::Context.new RClass: Gated
|
405
|
-
g1
|
431
|
+
g1 = cxt.eval 'var g1 = new RClass(1,2.3); g1'
|
406
432
|
g1.should be_a(Gated)
|
407
433
|
g2 = cxt.eval 'g1.checkself'
|
408
434
|
g2.should be_a(Gated)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: h8
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sergeych
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: hashie
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.1.2
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.1.2
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: pargser
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|