sax-machine 0.3.0 → 1.0.0
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/Gemfile +1 -0
- data/HISTORY.md +4 -0
- data/README.md +10 -12
- data/lib/sax-machine.rb +5 -1
- data/lib/sax-machine/config/sax_attribute.rb +1 -4
- data/lib/sax-machine/config/sax_element.rb +2 -1
- data/lib/sax-machine/handlers/sax_abstract_handler.rb +4 -5
- data/lib/sax-machine/sax_config.rb +1 -1
- data/lib/sax-machine/sax_document.rb +12 -3
- data/lib/sax-machine/version.rb +1 -1
- data/sax-machine.gemspec +0 -1
- data/spec/sax-machine/sax_activerecord_spec.rb +12 -14
- data/spec/sax-machine/sax_configure_spec.rb +26 -23
- data/spec/sax-machine/sax_document_spec.rb +74 -19
- data/spec/sax-machine/sax_include_spec.rb +18 -12
- data/spec/spec_helper.rb +1 -3
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0fb49e4c86a5d258cd1266f3b39f0279ff6ecc4
|
4
|
+
data.tar.gz: 9221aa8a9a9a552f1ac9ce7e5b962db2e5987515
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6da8e076f9d871aebfee80887b007712768c60643d5690b514cd886758583e132971417533afb560de2a4c8aee988131a46a62da28b32be9ed2837c7f4cf9e86
|
7
|
+
data.tar.gz: 8f28dd9652e24a9d853ded552df3ca25e80cba2eead23bb1ead8d331bc50768778938d7709ab3ebaa7cc11c3ebb411c74de119b8c64897f3d1ae7a41c3457911
|
data/Gemfile
CHANGED
data/HISTORY.md
CHANGED
data/README.md
CHANGED
@@ -28,30 +28,26 @@ $ bundle
|
|
28
28
|
|
29
29
|
## Usage
|
30
30
|
|
31
|
-
|
31
|
+
SAX Machine can use either `nokogiri` or `ox` as XML SAX handler.
|
32
|
+
|
33
|
+
To use **Nokogiri** add this line to your Gemfile:
|
32
34
|
|
33
35
|
```ruby
|
34
|
-
|
36
|
+
gem 'nokogiri', '~> 1.6'
|
35
37
|
```
|
36
38
|
|
37
|
-
To use **Ox**
|
38
|
-
|
39
|
-
Add this line to your application's Gemfile:
|
39
|
+
To use **Ox** add this line to your Gemfile:
|
40
40
|
|
41
41
|
```ruby
|
42
42
|
gem 'ox', '>= 2.1.2'
|
43
43
|
```
|
44
44
|
|
45
|
-
|
45
|
+
You can also specify which handler to use manually, like this:
|
46
46
|
|
47
47
|
```ruby
|
48
|
-
|
49
|
-
SAXMachine.handler = :ox
|
48
|
+
SAXMachine.handler = :nokogiri
|
50
49
|
```
|
51
50
|
|
52
|
-
Please note that this operation is not thread-safe, so it's better to define
|
53
|
-
handler at initialization stage and do not change it during runtime.
|
54
|
-
|
55
51
|
## Examples
|
56
52
|
|
57
53
|
Include `SAXMachine` in any class and define properties to parse:
|
@@ -69,7 +65,8 @@ class AtomEntry
|
|
69
65
|
# The :as argument makes this available through entry.author instead of .name
|
70
66
|
element :name, as: :author
|
71
67
|
element "feedburner:origLink", as: :url
|
72
|
-
element
|
68
|
+
# The :default argument specifies default value for element when it's missing
|
69
|
+
element :summary, class: String, default: "No summary available"
|
73
70
|
element :content, class: AtomContent
|
74
71
|
element :published
|
75
72
|
ancestor :ancestor
|
@@ -104,6 +101,7 @@ feed.feed_url # The URL of the blog feed
|
|
104
101
|
feed.entries.first.title # Title of the first entry
|
105
102
|
feed.entries.first.author # The author of the first entry
|
106
103
|
feed.entries.first.url # Permalink on the blog for this entry
|
104
|
+
feed.entries.first.summary # Returns "No summary available" if summary is missing
|
107
105
|
feed.entries.first.ancestor # The Atom ancestor
|
108
106
|
feed.entries.first.content # Instance of AtomContent
|
109
107
|
feed.entries.first.content.text # Entry content text
|
data/lib/sax-machine.rb
CHANGED
@@ -25,10 +25,7 @@ module SAXMachine
|
|
25
25
|
def attrs_match?(attrs)
|
26
26
|
attrs.key?(@name) || attrs.value?(@name)
|
27
27
|
end
|
28
|
-
|
29
|
-
def has_value_and_attrs_match?(attrs)
|
30
|
-
attrs_match?(attrs)
|
31
|
-
end
|
28
|
+
alias_method :has_value_and_attrs_match?, :attrs_match?
|
32
29
|
|
33
30
|
def collection?
|
34
31
|
false
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module SAXMachine
|
2
2
|
class SAXConfig
|
3
3
|
class ElementConfig
|
4
|
-
attr_reader :name, :setter, :data_class, :collection
|
4
|
+
attr_reader :name, :as, :setter, :data_class, :collection, :default
|
5
5
|
|
6
6
|
def initialize(name, options)
|
7
7
|
@name = name.to_s
|
@@ -15,6 +15,7 @@ module SAXMachine
|
|
15
15
|
|
16
16
|
@as = options[:as]
|
17
17
|
@collection = options[:collection]
|
18
|
+
@default = options[:default]
|
18
19
|
|
19
20
|
@setter = if @collection
|
20
21
|
"add_#{options[:as]}"
|
@@ -104,19 +104,18 @@ module SAXMachine
|
|
104
104
|
else
|
105
105
|
value =
|
106
106
|
case config.data_class.to_s
|
107
|
-
when "String" then value.to_s
|
108
|
-
when "Integer" then value.to_i
|
109
|
-
when "Float" then value.to_f
|
107
|
+
when "String" then value != NO_BUFFER ? value.to_s : value
|
108
|
+
when "Integer" then value != NO_BUFFER ? value.to_i : value
|
109
|
+
when "Float" then value != NO_BUFFER ? value.to_f : value
|
110
110
|
# Assumes that time elements will be string-based and are not
|
111
111
|
# something else, e.g. seconds since epoch
|
112
|
-
when "Time" then Time.parse(value.to_s)
|
112
|
+
when "Time" then value != NO_BUFFER ? Time.parse(value.to_s) : value
|
113
113
|
when "" then value
|
114
114
|
else
|
115
115
|
element
|
116
116
|
end
|
117
117
|
|
118
118
|
object.send(config.setter, value) unless value == NO_BUFFER
|
119
|
-
|
120
119
|
mark_as_parsed(object, config)
|
121
120
|
end
|
122
121
|
|
@@ -33,6 +33,15 @@ module SAXMachine
|
|
33
33
|
attributes.each do |name, value|
|
34
34
|
send("#{name}=", value)
|
35
35
|
end
|
36
|
+
|
37
|
+
self.class.sax_config.top_level_elements.each do |_, configs|
|
38
|
+
configs.each do |config|
|
39
|
+
next unless config.default
|
40
|
+
next unless send(config.as).nil?
|
41
|
+
|
42
|
+
send(config.setter, config.default)
|
43
|
+
end
|
44
|
+
end
|
36
45
|
end
|
37
46
|
end
|
38
47
|
|
@@ -48,19 +57,19 @@ module SAXMachine
|
|
48
57
|
def element(name, options = {})
|
49
58
|
real_name = (options[:as] ||= name).to_s
|
50
59
|
sax_config.add_top_level_element(name, options)
|
51
|
-
create_attr
|
60
|
+
create_attr(real_name)
|
52
61
|
end
|
53
62
|
|
54
63
|
def attribute(name, options = {})
|
55
64
|
real_name = (options[:as] ||= name).to_s
|
56
65
|
sax_config.add_top_level_attribute(self.class.to_s, options.merge(name: name))
|
57
|
-
create_attr
|
66
|
+
create_attr(real_name)
|
58
67
|
end
|
59
68
|
|
60
69
|
def value(name, options = {})
|
61
70
|
real_name = (options[:as] ||= name).to_s
|
62
71
|
sax_config.add_top_level_element_value(self.class.to_s, options.merge(name: name))
|
63
|
-
create_attr
|
72
|
+
create_attr(real_name)
|
64
73
|
end
|
65
74
|
|
66
75
|
def ancestor(name, options = {})
|
data/lib/sax-machine/version.rb
CHANGED
data/sax-machine.gemspec
CHANGED
@@ -1,23 +1,21 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
require 'active_record'
|
3
3
|
|
4
|
-
describe "ActiveRecord" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
c.element :title
|
10
|
-
end
|
4
|
+
describe "SAXMachine ActiveRecord integration" do
|
5
|
+
before do
|
6
|
+
class MySaxModel < ActiveRecord::Base
|
7
|
+
SAXMachine.configure(MySaxModel) do |c|
|
8
|
+
c.element :title
|
11
9
|
end
|
12
10
|
end
|
11
|
+
end
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
after do
|
14
|
+
Object.send(:remove_const, :MySaxModel)
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
17
|
+
it "parses document" do
|
18
|
+
document = MySaxModel.parse("<xml><title>My Title</title></xml>")
|
19
|
+
expect(document.title).to eq("My Title")
|
22
20
|
end
|
23
21
|
end
|
@@ -1,32 +1,35 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
describe "SAXMachine configure" do
|
4
|
+
before do
|
5
|
+
class A
|
6
|
+
SAXMachine.configure(A) do |c|
|
7
|
+
c.element :title
|
8
|
+
end
|
9
|
+
end
|
8
10
|
|
9
|
-
class B < A
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
11
|
+
class B < A
|
12
|
+
SAXMachine.configure(B) do |c|
|
13
|
+
c.element :b
|
14
|
+
end
|
15
|
+
end
|
14
16
|
|
15
|
-
class C < B
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
17
|
+
class C < B
|
18
|
+
SAXMachine.configure(C) do |c|
|
19
|
+
c.element :c
|
20
|
+
end
|
21
|
+
end
|
20
22
|
|
21
|
-
describe "SAXMachine configure" do
|
22
|
-
before do
|
23
23
|
xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
|
24
|
-
@a = A.
|
25
|
-
@
|
26
|
-
@
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
@a = A.parse xml
|
25
|
+
@b = B.parse xml
|
26
|
+
@c = C.parse xml
|
27
|
+
end
|
28
|
+
|
29
|
+
after do
|
30
|
+
Object.send(:remove_const, :A)
|
31
|
+
Object.send(:remove_const, :B)
|
32
|
+
Object.send(:remove_const, :C)
|
30
33
|
end
|
31
34
|
|
32
35
|
it { expect(@a).to be_a(A) }
|
@@ -3,10 +3,13 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
3
3
|
describe "SAXMachine" do
|
4
4
|
describe "element" do
|
5
5
|
describe "when parsing a single element" do
|
6
|
-
before
|
6
|
+
before do
|
7
7
|
@klass = Class.new do
|
8
8
|
include SAXMachine
|
9
9
|
element :title
|
10
|
+
ancestor :body
|
11
|
+
value :something, required: false
|
12
|
+
attribute :anything, required: true
|
10
13
|
end
|
11
14
|
end
|
12
15
|
|
@@ -21,10 +24,6 @@ describe "SAXMachine" do
|
|
21
24
|
expect(document.title).to eq("Title")
|
22
25
|
end
|
23
26
|
|
24
|
-
it "allows introspection of the elements" do
|
25
|
-
expect(@klass.column_names).to match_array([:title])
|
26
|
-
end
|
27
|
-
|
28
27
|
it "does not overwrites the getter is there is already one present" do
|
29
28
|
@klass = Class.new do
|
30
29
|
def title
|
@@ -97,6 +96,38 @@ describe "SAXMachine" do
|
|
97
96
|
expect(document.title).to eq("My Title")
|
98
97
|
end
|
99
98
|
|
99
|
+
describe "the introspection" do
|
100
|
+
it "allows to get column names" do
|
101
|
+
expect(@klass.column_names).to match_array([:title])
|
102
|
+
end
|
103
|
+
|
104
|
+
it "allows to get elements" do
|
105
|
+
expect(@klass.sax_config.top_level_elements.values.flatten.map(&:to_s)).to \
|
106
|
+
match_array(["name: title dataclass: setter: title= required: value: as:title collection: with: {}"])
|
107
|
+
end
|
108
|
+
|
109
|
+
it "allows to get ancestors" do
|
110
|
+
expect(@klass.sax_config.ancestors.map(&:column)).to \
|
111
|
+
match_array([:body])
|
112
|
+
end
|
113
|
+
|
114
|
+
it "allows to get values" do
|
115
|
+
expect(@klass.sax_config.top_level_element_value.map(&:column)).to \
|
116
|
+
match_array([:something])
|
117
|
+
expect(@klass.sax_config.top_level_element_value.map(&:required?)).to \
|
118
|
+
match_array([false])
|
119
|
+
end
|
120
|
+
|
121
|
+
it "allows to get attributes" do
|
122
|
+
expect(@klass.sax_config.top_level_attributes.map(&:column)).to \
|
123
|
+
match_array([:anything])
|
124
|
+
expect(@klass.sax_config.top_level_attributes.map(&:required?)).to \
|
125
|
+
match_array([true])
|
126
|
+
expect(@klass.sax_config.top_level_attributes.map(&:collection?)).to \
|
127
|
+
match_array([false])
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
100
131
|
describe "the class attribute" do
|
101
132
|
before(:each) do
|
102
133
|
@klass = Class.new do
|
@@ -153,6 +184,21 @@ describe "SAXMachine" do
|
|
153
184
|
end
|
154
185
|
end
|
155
186
|
|
187
|
+
describe "the default attribute" do
|
188
|
+
it "is available" do
|
189
|
+
@klass = Class.new do
|
190
|
+
include SAXMachine
|
191
|
+
element :number, class: Integer, default: 0
|
192
|
+
end
|
193
|
+
|
194
|
+
document = @klass.parse("<no>number</no>")
|
195
|
+
expect(document.number).to eq(0)
|
196
|
+
|
197
|
+
document = @klass.parse("<number></number>")
|
198
|
+
expect(document.number).to eq(0)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
156
202
|
describe "the required attribute" do
|
157
203
|
it "is available" do
|
158
204
|
@klass = Class.new do
|
@@ -165,7 +211,7 @@ describe "SAXMachine" do
|
|
165
211
|
end
|
166
212
|
|
167
213
|
describe "when parsing multiple elements" do
|
168
|
-
before
|
214
|
+
before do
|
169
215
|
@klass = Class.new do
|
170
216
|
include SAXMachine
|
171
217
|
element :title
|
@@ -212,7 +258,7 @@ describe "SAXMachine" do
|
|
212
258
|
|
213
259
|
describe "when using options for parsing elements" do
|
214
260
|
describe "using the 'as' option" do
|
215
|
-
before
|
261
|
+
before do
|
216
262
|
@klass = Class.new do
|
217
263
|
include SAXMachine
|
218
264
|
element :description, as: :summary
|
@@ -233,7 +279,7 @@ describe "SAXMachine" do
|
|
233
279
|
|
234
280
|
describe "using the :with option" do
|
235
281
|
describe "and the :value option" do
|
236
|
-
before
|
282
|
+
before do
|
237
283
|
@klass = Class.new do
|
238
284
|
include SAXMachine
|
239
285
|
element :link, value: :href, with: { foo: "bar" }
|
@@ -251,7 +297,7 @@ describe "SAXMachine" do
|
|
251
297
|
end
|
252
298
|
|
253
299
|
describe "and the :as option" do
|
254
|
-
before
|
300
|
+
before do
|
255
301
|
@klass = Class.new do
|
256
302
|
include SAXMachine
|
257
303
|
element :link, value: :href, as: :url, with: { foo: "bar" }
|
@@ -268,7 +314,7 @@ describe "SAXMachine" do
|
|
268
314
|
end
|
269
315
|
|
270
316
|
describe "with only one element" do
|
271
|
-
before
|
317
|
+
before do
|
272
318
|
@klass = Class.new do
|
273
319
|
include SAXMachine
|
274
320
|
element :link, with: { foo: "bar" }
|
@@ -297,7 +343,7 @@ describe "SAXMachine" do
|
|
297
343
|
end
|
298
344
|
|
299
345
|
describe "with multiple elements of same tag" do
|
300
|
-
before
|
346
|
+
before do
|
301
347
|
@klass = Class.new do
|
302
348
|
include SAXMachine
|
303
349
|
element :link, as: :first, with: { foo: "bar" }
|
@@ -317,7 +363,7 @@ describe "SAXMachine" do
|
|
317
363
|
end
|
318
364
|
|
319
365
|
describe "with only one element as a regular expression" do
|
320
|
-
before
|
366
|
+
before do
|
321
367
|
@klass = Class.new do
|
322
368
|
include SAXMachine
|
323
369
|
element :link, with: { foo: /ar$/ }
|
@@ -347,7 +393,7 @@ describe "SAXMachine" do
|
|
347
393
|
end
|
348
394
|
|
349
395
|
describe "using the 'value' option" do
|
350
|
-
before
|
396
|
+
before do
|
351
397
|
@klass = Class.new do
|
352
398
|
include SAXMachine
|
353
399
|
element :link, value: :foo
|
@@ -395,7 +441,7 @@ describe "SAXMachine" do
|
|
395
441
|
end
|
396
442
|
|
397
443
|
describe "when desiring both the content and attributes of an element" do
|
398
|
-
before
|
444
|
+
before do
|
399
445
|
@klass = Class.new do
|
400
446
|
include SAXMachine
|
401
447
|
element :link
|
@@ -416,7 +462,7 @@ describe "SAXMachine" do
|
|
416
462
|
|
417
463
|
describe "elements" do
|
418
464
|
describe "when parsing multiple elements" do
|
419
|
-
before
|
465
|
+
before do
|
420
466
|
@klass = Class.new do
|
421
467
|
include SAXMachine
|
422
468
|
elements :entry, as: :entries
|
@@ -451,7 +497,7 @@ describe "SAXMachine" do
|
|
451
497
|
end
|
452
498
|
|
453
499
|
describe "when using the with and class options" do
|
454
|
-
before
|
500
|
+
before do
|
455
501
|
class Bar
|
456
502
|
include SAXMachine
|
457
503
|
element :title
|
@@ -484,7 +530,7 @@ describe "SAXMachine" do
|
|
484
530
|
end
|
485
531
|
|
486
532
|
describe "when using the class option" do
|
487
|
-
before
|
533
|
+
before do
|
488
534
|
class Foo
|
489
535
|
include SAXMachine
|
490
536
|
element :title
|
@@ -559,7 +605,7 @@ describe "SAXMachine" do
|
|
559
605
|
end
|
560
606
|
|
561
607
|
describe "full example" do
|
562
|
-
before
|
608
|
+
before do
|
563
609
|
@xml = File.read("spec/fixtures/atom.xml")
|
564
610
|
|
565
611
|
class AtomEntry
|
@@ -881,11 +927,20 @@ describe "SAXMachine" do
|
|
881
927
|
end
|
882
928
|
|
883
929
|
@errors = []
|
884
|
-
@
|
930
|
+
@warnings = []
|
931
|
+
@item = ItemElement5.parse(
|
932
|
+
@xml,
|
933
|
+
->(x) { @errors << x },
|
934
|
+
->(x) { @warnings << x },
|
935
|
+
)
|
885
936
|
end
|
886
937
|
|
887
938
|
it "has error" do
|
888
939
|
expect(@errors.uniq.size).to eq(1)
|
889
940
|
end
|
941
|
+
|
942
|
+
it "has no warning" do
|
943
|
+
expect(@warnings.uniq.size).to eq(0)
|
944
|
+
end
|
890
945
|
end
|
891
946
|
end
|
@@ -1,20 +1,20 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
describe "SAXMachine inheritance" do
|
4
|
+
before do
|
5
|
+
class A
|
6
|
+
include SAXMachine
|
7
|
+
element :title
|
8
|
+
end
|
7
9
|
|
8
|
-
class B < A
|
9
|
-
|
10
|
-
end
|
10
|
+
class B < A
|
11
|
+
element :b
|
12
|
+
end
|
11
13
|
|
12
|
-
class C < B
|
13
|
-
|
14
|
-
end
|
14
|
+
class C < B
|
15
|
+
element :c
|
16
|
+
end
|
15
17
|
|
16
|
-
describe "SAXMachine inheritance" do
|
17
|
-
before do
|
18
18
|
xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
|
19
19
|
@a = A.new
|
20
20
|
@a.parse xml
|
@@ -24,6 +24,12 @@ describe "SAXMachine inheritance" do
|
|
24
24
|
@c.parse xml
|
25
25
|
end
|
26
26
|
|
27
|
+
after do
|
28
|
+
Object.send(:remove_const, :A)
|
29
|
+
Object.send(:remove_const, :B)
|
30
|
+
Object.send(:remove_const, :C)
|
31
|
+
end
|
32
|
+
|
27
33
|
it { expect(@a).to be_a(A) }
|
28
34
|
it { expect(@a).not_to be_a(B) }
|
29
35
|
it { expect(@a).to be_a(SAXMachine) }
|
data/spec/spec_helper.rb
CHANGED
@@ -14,9 +14,7 @@ rescue LoadError
|
|
14
14
|
end
|
15
15
|
|
16
16
|
require File.expand_path(File.dirname(__FILE__) + '/../lib/sax-machine')
|
17
|
-
|
18
|
-
SAXMachine.handler = :ox
|
19
|
-
end
|
17
|
+
SAXMachine.handler = ENV['HANDLER'].to_sym
|
20
18
|
|
21
19
|
RSpec.configure do |config|
|
22
20
|
config.run_all_when_everything_filtered = true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sax-machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Dix
|
@@ -11,22 +11,8 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2014-
|
14
|
+
date: 2014-08-05 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
17
|
-
name: nokogiri
|
18
|
-
requirement: !ruby/object:Gem::Requirement
|
19
|
-
requirements:
|
20
|
-
- - "~>"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 1.6.0
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 1.6.0
|
30
16
|
- !ruby/object:Gem::Dependency
|
31
17
|
name: rspec
|
32
18
|
requirement: !ruby/object:Gem::Requirement
|