ParseTree 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +22 -0
- data/bin/parse_tree_show +28 -34
- data/lib/parse_tree.rb +4 -1
- data/lib/sexp.rb +1 -1
- data/lib/sexp_processor.rb +31 -20
- data/lib/unified_ruby.rb +50 -15
- data/test/test_composite_sexp_processor.rb +5 -4
- data/test/test_sexp.rb +2 -0
- data/test/test_unified_ruby.rb +82 -38
- metadata +3 -3
data/History.txt
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
=== 2.0.1 / 2007-08-21
|
2
|
+
|
3
|
+
* 1 major enhancement:
|
4
|
+
|
5
|
+
* Rewrote parse_tree_show to use parse_tree_for_string.
|
6
|
+
* parse_tree_show adds -n=node filtering -u unifying, and -s structure-only.
|
7
|
+
* parse_tree_show no longer needs -f
|
8
|
+
|
9
|
+
* 4 minor enhancements:
|
10
|
+
|
11
|
+
* Added context stack to SexpProcessor! YAY!!!
|
12
|
+
* Enforce type to be symbol in SexpProcessor... just makes life easier.
|
13
|
+
* Processing style change mode to UnifiedRuby. Prefer no rescues.
|
14
|
+
* Sexp#structure is no longer destructive.
|
15
|
+
|
16
|
+
* 4 bug fixes:
|
17
|
+
|
18
|
+
* Added 1.8.4 compatibility fix.
|
19
|
+
* Added args lifting in :defs in UnifiedRuby.
|
20
|
+
* Fixed unifying argscat, splat, and a couple other oddities.
|
21
|
+
* Added process_call to UnifiedRuby *sigh* I'm a tard.
|
22
|
+
|
1
23
|
=== 2.0.0 / 2007-08-01
|
2
24
|
|
3
25
|
* 2 major enhancements:
|
data/bin/parse_tree_show
CHANGED
@@ -3,47 +3,41 @@
|
|
3
3
|
require 'pp'
|
4
4
|
begin require 'rubygems' rescue LoadError end
|
5
5
|
require 'parse_tree'
|
6
|
+
require 'sexp'
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
8
|
+
$u ||= false
|
9
|
+
$n ||= false
|
10
|
+
$s ||= false
|
11
|
+
$n = $n.intern if $n
|
12
12
|
|
13
|
-
|
13
|
+
ARGV.push "-" if ARGV.empty?
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
15
|
+
if $u then
|
16
|
+
require 'sexp_processor'
|
17
|
+
require 'unified_ruby'
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
new_classes
|
23
|
-
end
|
24
|
-
|
25
|
-
$f = false unless defined? $f
|
26
|
-
|
27
|
-
new_classes = discover_new_classes_from do
|
28
|
-
ARGV.unshift "-" if ARGV.empty?
|
29
|
-
ARGV.each do |name|
|
30
|
-
if name == "-" then
|
31
|
-
code = $stdin.read
|
32
|
-
code = "class Example; def example; #{code}; end; end" if $f
|
33
|
-
eval code unless code.nil?
|
34
|
-
else
|
35
|
-
require name
|
36
|
-
end
|
19
|
+
class Unifier < SexpProcessor
|
20
|
+
include UnifiedRuby
|
37
21
|
end
|
38
22
|
end
|
39
23
|
|
40
|
-
|
24
|
+
parse_tree = ParseTree.new
|
25
|
+
unifier = Unifier.new if $u
|
41
26
|
|
42
|
-
|
27
|
+
ARGV.each do |file|
|
28
|
+
ruby = file == "-" ? $stdin.read : File.read(file)
|
43
29
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
p result
|
48
|
-
end
|
30
|
+
sexp = Sexp.from_array parse_tree.parse_tree_for_string(ruby, file).first
|
31
|
+
sexp = unifier.process(sexp) if $u
|
32
|
+
sexp = sexp.structure if $s
|
49
33
|
|
34
|
+
if $n then
|
35
|
+
sexp.each_of_type $n do |node|
|
36
|
+
p node
|
37
|
+
end
|
38
|
+
elsif defined? $q then
|
39
|
+
p sexp
|
40
|
+
else
|
41
|
+
pp sexp
|
42
|
+
end
|
43
|
+
end
|
data/lib/parse_tree.rb
CHANGED
@@ -41,7 +41,7 @@ end
|
|
41
41
|
|
42
42
|
class ParseTree
|
43
43
|
|
44
|
-
VERSION = '2.0.
|
44
|
+
VERSION = '2.0.1'
|
45
45
|
|
46
46
|
##
|
47
47
|
# Front end translation method.
|
@@ -811,6 +811,9 @@ again_no_block:
|
|
811
811
|
// nothing to do in this case, handled above
|
812
812
|
} else if (arg_count == -2) {
|
813
813
|
// nothing to do in this case, no name == no use
|
814
|
+
#if RUBY_VERSION_CODE < 185
|
815
|
+
rb_ary_push(current, rb_str_intern(rb_str_new2("*")));
|
816
|
+
#endif
|
814
817
|
} else {
|
815
818
|
rb_raise(rb_eArgError,
|
816
819
|
"not a clue what this arg value is: %ld", arg_count);
|
data/lib/sexp.rb
CHANGED
data/lib/sexp_processor.rb
CHANGED
@@ -74,17 +74,6 @@ class SexpTypeError < SexpProcessorError; end
|
|
74
74
|
|
75
75
|
class SexpProcessor
|
76
76
|
|
77
|
-
##
|
78
|
-
# A default method to call if a process_<type> method is not found
|
79
|
-
# for the Sexp type.
|
80
|
-
|
81
|
-
attr_accessor :default_method
|
82
|
-
|
83
|
-
##
|
84
|
-
# Emit a warning when the method in #default_method is called.
|
85
|
-
|
86
|
-
attr_accessor :warn_on_default
|
87
|
-
|
88
77
|
##
|
89
78
|
# Automatically shifts off the Sexp type before handing the
|
90
79
|
# Sexp to process_<type>
|
@@ -92,16 +81,9 @@ class SexpProcessor
|
|
92
81
|
attr_accessor :auto_shift_type
|
93
82
|
|
94
83
|
##
|
95
|
-
#
|
96
|
-
# processor. SexpProcessor will raise UnsupportedNodeError if you try
|
97
|
-
# to process one of those node types.
|
84
|
+
# Return a stack of contexts. Most recent node is first.
|
98
85
|
|
99
|
-
|
100
|
-
|
101
|
-
##
|
102
|
-
# Raise an exception if no process_<type> method is found for a Sexp.
|
103
|
-
|
104
|
-
attr_accessor :strict
|
86
|
+
attr_reader :context
|
105
87
|
|
106
88
|
##
|
107
89
|
# A Hash of Sexp types and Regexp.
|
@@ -111,6 +93,12 @@ class SexpProcessor
|
|
111
93
|
|
112
94
|
attr_accessor :debug
|
113
95
|
|
96
|
+
##
|
97
|
+
# A default method to call if a process_<type> method is not found
|
98
|
+
# for the Sexp type.
|
99
|
+
|
100
|
+
attr_accessor :default_method
|
101
|
+
|
114
102
|
##
|
115
103
|
# Expected result class
|
116
104
|
|
@@ -121,6 +109,23 @@ class SexpProcessor
|
|
121
109
|
|
122
110
|
attr_accessor :require_empty
|
123
111
|
|
112
|
+
##
|
113
|
+
# Raise an exception if no process_<type> method is found for a Sexp.
|
114
|
+
|
115
|
+
attr_accessor :strict
|
116
|
+
|
117
|
+
##
|
118
|
+
# An array that specifies node types that are unsupported by this
|
119
|
+
# processor. SexpProcessor will raise UnsupportedNodeError if you try
|
120
|
+
# to process one of those node types.
|
121
|
+
|
122
|
+
attr_accessor :unsupported
|
123
|
+
|
124
|
+
##
|
125
|
+
# Emit a warning when the method in #default_method is called.
|
126
|
+
|
127
|
+
attr_accessor :warn_on_default
|
128
|
+
|
124
129
|
##
|
125
130
|
# Creates a new SexpProcessor. Use super to invoke this
|
126
131
|
# initializer from SexpProcessor subclasses, then use the
|
@@ -144,6 +149,7 @@ class SexpProcessor
|
|
144
149
|
# different processors.
|
145
150
|
@processors = {}
|
146
151
|
@rewriters = {}
|
152
|
+
@context = []
|
147
153
|
|
148
154
|
public_methods.each do |name|
|
149
155
|
case name
|
@@ -198,6 +204,10 @@ class SexpProcessor
|
|
198
204
|
result = self.expected.new
|
199
205
|
|
200
206
|
type = exp.first
|
207
|
+
raise "type should be a Symbol, not: #{exp.first.inspect}" unless
|
208
|
+
Symbol === type
|
209
|
+
|
210
|
+
@context.unshift type
|
201
211
|
|
202
212
|
if @debug.has_key? type then
|
203
213
|
str = exp.inspect
|
@@ -268,6 +278,7 @@ class SexpProcessor
|
|
268
278
|
|
269
279
|
@process_level -= 1
|
270
280
|
|
281
|
+
@context.shift
|
271
282
|
result
|
272
283
|
end
|
273
284
|
|
data/lib/unified_ruby.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
|
2
|
+
$TESTING ||= false
|
3
|
+
|
2
4
|
module UnifiedRuby
|
5
|
+
def rewrite_argscat(exp)
|
6
|
+
raise "unknown type #{exp.inspect}" unless exp[1][0] == :array
|
7
|
+
exp[1][0] = :arglist
|
8
|
+
exp
|
9
|
+
end
|
10
|
+
|
3
11
|
def rewrite_bmethod(exp)
|
4
12
|
exp[0] = :scope
|
5
13
|
|
@@ -25,6 +33,28 @@ module UnifiedRuby
|
|
25
33
|
exp
|
26
34
|
end
|
27
35
|
|
36
|
+
def rewrite_call(exp)
|
37
|
+
args = exp.last
|
38
|
+
case args
|
39
|
+
when nil
|
40
|
+
exp.pop
|
41
|
+
when Array
|
42
|
+
case args.first
|
43
|
+
when :array, :arglist then
|
44
|
+
args[0] = :arglist
|
45
|
+
when :argscat, :splat then
|
46
|
+
# do nothing
|
47
|
+
else
|
48
|
+
raise "unknown type in call #{args.first.inspect}"
|
49
|
+
end
|
50
|
+
return exp
|
51
|
+
end
|
52
|
+
|
53
|
+
exp << s(:arglist)
|
54
|
+
|
55
|
+
exp
|
56
|
+
end
|
57
|
+
|
28
58
|
##
|
29
59
|
# :defn is one of the most complex of all the ASTs in ruby. We do
|
30
60
|
# one of 3 different translations:
|
@@ -74,6 +104,14 @@ module UnifiedRuby
|
|
74
104
|
exp
|
75
105
|
end
|
76
106
|
|
107
|
+
def rewrite_defs(exp)
|
108
|
+
# move args up
|
109
|
+
args = exp.scope.block.args(true) rescue nil
|
110
|
+
exp.insert 3, args if args
|
111
|
+
|
112
|
+
exp
|
113
|
+
end
|
114
|
+
|
77
115
|
def rewrite_dmethod(exp)
|
78
116
|
exp.shift # type
|
79
117
|
exp.shift # dmethod name
|
@@ -89,16 +127,7 @@ module UnifiedRuby
|
|
89
127
|
exp.insert 1, nil
|
90
128
|
exp.push nil if exp.size <= 3
|
91
129
|
|
92
|
-
|
93
|
-
if Array === args and args.first == :array then
|
94
|
-
args[0] = :arglist
|
95
|
-
elsif args.nil? then
|
96
|
-
exp[-1] = s(:arglist)
|
97
|
-
else
|
98
|
-
exp[-1] = s(:arglist, args) unless args.nil?
|
99
|
-
end
|
100
|
-
|
101
|
-
exp
|
130
|
+
rewrite_call(exp)
|
102
131
|
end
|
103
132
|
|
104
133
|
def rewrite_resbody(exp) # TODO: clean up and move to unified
|
@@ -108,8 +137,8 @@ module UnifiedRuby
|
|
108
137
|
while exp and exp.first == :resbody do
|
109
138
|
code << exp.shift
|
110
139
|
list = exp.shift || s(:array)
|
111
|
-
body = exp.
|
112
|
-
exp = exp.
|
140
|
+
body = exp.empty? ? nil : exp.shift
|
141
|
+
exp = exp.empty? ? nil : exp.shift
|
113
142
|
|
114
143
|
# code may be nil, :lasgn, or :block
|
115
144
|
case body.first
|
@@ -133,9 +162,15 @@ module UnifiedRuby
|
|
133
162
|
end
|
134
163
|
end
|
135
164
|
|
136
|
-
|
137
|
-
|
138
|
-
|
165
|
+
if $DEBUG or $TESTING then
|
166
|
+
structure = result.structure
|
167
|
+
raise "result structure wrong: #{structure[0..1].inspect}" unless
|
168
|
+
structure.flatten[0] == :resbody
|
169
|
+
raise "result structure wrong: #{structure[0..1].inspect}" unless
|
170
|
+
s(:array, :splat, :argscat).include? structure.flatten[1]
|
171
|
+
raise "result body wrong: #{structure[2].inspect}" unless
|
172
|
+
structure[2].nil? or not structure[2].empty?
|
173
|
+
end
|
139
174
|
|
140
175
|
result
|
141
176
|
end
|
@@ -16,6 +16,7 @@ class FakeProcessor1 < SexpProcessor # ZenTest SKIP
|
|
16
16
|
|
17
17
|
def default_processor(exp)
|
18
18
|
result = []
|
19
|
+
result << exp.shift
|
19
20
|
until exp.empty? do
|
20
21
|
result << exp.shift.to_s + " woot"
|
21
22
|
end
|
@@ -36,18 +37,18 @@ class TestCompositeSexpProcessor < Test::Unit::TestCase
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def test_process_fake1
|
39
|
-
data = [1, 2, 3]
|
40
|
+
data = [:x, 1, 2, 3]
|
40
41
|
@p << FakeProcessor1.new
|
41
42
|
result = @p.process(data.dup)
|
42
|
-
assert_equal
|
43
|
+
assert_equal [:x, "1 woot", "2 woot", "3 woot"], result
|
43
44
|
end
|
44
45
|
|
45
46
|
def test_process_fake1_twice
|
46
|
-
data = [1, 2, 3]
|
47
|
+
data = [:x, 1, 2, 3]
|
47
48
|
@p << FakeProcessor1.new
|
48
49
|
@p << FakeProcessor1.new
|
49
50
|
result = @p.process(data.dup)
|
50
|
-
assert_equal
|
51
|
+
assert_equal [:x, "1 woot woot", "2 woot woot", "3 woot woot"], result
|
51
52
|
end
|
52
53
|
|
53
54
|
def test_processors
|
data/test/test_sexp.rb
CHANGED
@@ -263,9 +263,11 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
263
263
|
|
264
264
|
def test_structure
|
265
265
|
@sexp = s(:a, 1, 2, s(:b, 3, 4), 5, 6)
|
266
|
+
backup = @sexp.deep_clone
|
266
267
|
expected = s(:a, s(:b))
|
267
268
|
|
268
269
|
assert_equal(expected, @sexp.structure)
|
270
|
+
assert_equal(backup, @sexp)
|
269
271
|
end
|
270
272
|
|
271
273
|
def test_sub
|
data/test/test_unified_ruby.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/local/bin/ruby
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
2
|
|
3
3
|
$TESTING = true
|
4
4
|
|
@@ -31,6 +31,38 @@ class TestUnifiedRuby < Test::Unit::TestCase
|
|
31
31
|
assert_equal @expect, @sp.process(@insert)
|
32
32
|
end
|
33
33
|
|
34
|
+
def test_argscat
|
35
|
+
@insert = s(:argscat,
|
36
|
+
s(:array, s(:lvar, :container), s(:lvar, :point)),
|
37
|
+
s(:lvar, :args))
|
38
|
+
@expect = s(:argscat,
|
39
|
+
s(:arglist, s(:lvar, :container), s(:lvar, :point)),
|
40
|
+
s(:lvar, :args))
|
41
|
+
|
42
|
+
doit
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_call_args
|
46
|
+
@insert = s(:call, s(:lit, 42), :y, s(:array, s(:lit, 24)))
|
47
|
+
@expect = s(:call, s(:lit, 42), :y, s(:arglist, s(:lit, 24)))
|
48
|
+
|
49
|
+
doit
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_call_array_args
|
53
|
+
@insert = s(:call, s(:lit, 42), :y, s(:array))
|
54
|
+
@expect = s(:call, s(:lit, 42), :y, s(:arglist))
|
55
|
+
|
56
|
+
doit
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_call_no_args
|
60
|
+
@insert = s(:call, s(:lit, 42), :y)
|
61
|
+
@expect = s(:call, s(:lit, 42), :y, s(:arglist))
|
62
|
+
|
63
|
+
doit
|
64
|
+
end
|
65
|
+
|
34
66
|
def test_rewrite_bmethod
|
35
67
|
@insert = s(:bmethod,
|
36
68
|
s(:dasgn_curr, :x),
|
@@ -38,7 +70,7 @@ class TestUnifiedRuby < Test::Unit::TestCase
|
|
38
70
|
@expect = s(:scope,
|
39
71
|
s(:block,
|
40
72
|
s(:args, :x),
|
41
|
-
s(:call, s(:lvar, :x), :+, s(:
|
73
|
+
s(:call, s(:lvar, :x), :+, s(:arglist, s(:lit, 1)))))
|
42
74
|
|
43
75
|
doit
|
44
76
|
end
|
@@ -51,7 +83,7 @@ class TestUnifiedRuby < Test::Unit::TestCase
|
|
51
83
|
s(:block,
|
52
84
|
s(:args),
|
53
85
|
s(:call, s(:call, nil, :x, s(:arglist)),
|
54
|
-
:+, s(:
|
86
|
+
:+, s(:arglist, s(:lit, 1)))))
|
55
87
|
|
56
88
|
doit
|
57
89
|
end
|
@@ -98,7 +130,36 @@ class TestUnifiedRuby < Test::Unit::TestCase
|
|
98
130
|
s(:block_pass,
|
99
131
|
s(:lvar, :block),
|
100
132
|
s(:call, nil, :other,
|
101
|
-
s(:
|
133
|
+
s(:splat, s(:lvar, :args)))))))
|
134
|
+
|
135
|
+
doit
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_rewrite_defn_bmethod_alias
|
139
|
+
@insert = s(:defn, :group,
|
140
|
+
s(:fbody,
|
141
|
+
s(:bmethod,
|
142
|
+
s(:masgn, s(:dasgn_curr, :params)),
|
143
|
+
s(:block,
|
144
|
+
s(:lit, 42)))))
|
145
|
+
@expect = s(:defn, :group,
|
146
|
+
s(:args, :"*params"),
|
147
|
+
s(:scope,
|
148
|
+
s(:block, s(:lit, 42))))
|
149
|
+
|
150
|
+
doit
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_rewrite_defn_ivar
|
154
|
+
@insert = s(:defn, :reader, s(:ivar, :@reader))
|
155
|
+
@expect = s(:defn, :reader, s(:args), s(:ivar, :@reader))
|
156
|
+
|
157
|
+
doit
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_rewrite_defs
|
161
|
+
@insert = s(:defs, s(:self), :meth, s(:scope, s(:block, s(:args), s(:true))))
|
162
|
+
@expect = s(:defs, s(:self), :meth, s(:args), s(:scope, s(:block, s(:true))))
|
102
163
|
|
103
164
|
doit
|
104
165
|
end
|
@@ -127,23 +188,28 @@ class TestUnifiedRuby < Test::Unit::TestCase
|
|
127
188
|
@expect = s(:scope,
|
128
189
|
s(:block,
|
129
190
|
s(:args, :x),
|
130
|
-
s(:call, s(:lvar, :x), :+, s(:
|
191
|
+
s(:call, s(:lvar, :x), :+, s(:arglist, s(:lit, 1)))))
|
131
192
|
|
132
193
|
doit
|
133
194
|
end
|
134
195
|
|
135
|
-
def
|
136
|
-
@insert = s(:
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
196
|
+
def test_rewrite_fcall
|
197
|
+
@insert = s(:fcall, :puts, s(:array, s(:lit, :blah)))
|
198
|
+
@expect = s(:call, nil, :puts, s(:arglist, s(:lit, :blah)))
|
199
|
+
|
200
|
+
doit
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_rewrite_fcall_loop
|
204
|
+
@insert = s(:iter, s(:fcall, :loop), nil)
|
205
|
+
@expect = s(:iter, s(:call, nil, :loop, s(:arglist)), nil)
|
206
|
+
|
207
|
+
doit
|
208
|
+
end
|
146
209
|
|
210
|
+
def test_rewrite_fcall_splat
|
211
|
+
@insert = s(:fcall, :method, s(:splat, s(:vcall, :a)))
|
212
|
+
@expect = s(:call, nil, :method, s(:splat, s(:call, nil, :a, s(:arglist))))
|
147
213
|
doit
|
148
214
|
end
|
149
215
|
|
@@ -198,32 +264,10 @@ class TestUnifiedRuby < Test::Unit::TestCase
|
|
198
264
|
doit
|
199
265
|
end
|
200
266
|
|
201
|
-
def test_rewrite_defn_ivar
|
202
|
-
@insert = s(:defn, :reader, s(:ivar, :@reader))
|
203
|
-
@expect = s(:defn, :reader, s(:args), s(:ivar, :@reader))
|
204
|
-
|
205
|
-
doit
|
206
|
-
end
|
207
|
-
|
208
267
|
def test_rewrite_vcall
|
209
268
|
@insert = s(:vcall, :puts)
|
210
269
|
@expect = s(:call, nil, :puts, s(:arglist))
|
211
270
|
|
212
271
|
doit
|
213
272
|
end
|
214
|
-
|
215
|
-
def test_rewrite_fcall
|
216
|
-
@insert = s(:fcall, :puts, s(:array, s(:lit, :blah)))
|
217
|
-
@expect = s(:call, nil, :puts, s(:arglist, s(:lit, :blah)))
|
218
|
-
|
219
|
-
doit
|
220
|
-
end
|
221
|
-
|
222
|
-
def test_rewrite_fcall_loop
|
223
|
-
@insert = s(:iter, s(:fcall, :loop), nil)
|
224
|
-
@expect = s(:iter, s(:call, nil, :loop, s(:arglist)), nil)
|
225
|
-
|
226
|
-
doit
|
227
|
-
end
|
228
|
-
|
229
273
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ParseTree
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 2.0.
|
7
|
-
date: 2007-08-
|
6
|
+
version: 2.0.1
|
7
|
+
date: 2007-08-21 00:00:00 -07:00
|
8
8
|
summary: ParseTree is a C extension (using RubyInline) that extracts the parse tree for an entire class or a specific method and returns it as a s-expression (aka sexp) using ruby's arrays, strings, symbols, and integers.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -89,5 +89,5 @@ dependencies:
|
|
89
89
|
requirements:
|
90
90
|
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: 1.
|
92
|
+
version: 1.3.0
|
93
93
|
version:
|