jnunemaker-happymapper 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History +7 -0
- data/Rakefile +1 -1
- data/TODO +0 -1
- data/examples/amazon.rb +5 -0
- data/examples/current_weather.rb +2 -0
- data/examples/dashed_elements.rb +1 -1
- data/happymapper.gemspec +4 -4
- data/lib/happymapper.rb +48 -36
- data/lib/happymapper/item.rb +45 -14
- data/lib/happymapper/version.rb +1 -1
- data/lib/libxml_ext/libxml_helper.rb +1 -3
- data/spec/fixtures/pita.xml +2 -1
- data/spec/happymapper_item_spec.rb +1 -1
- data/spec/happymapper_spec.rb +31 -8
- metadata +3 -3
data/History
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.2.1
|
2
|
+
* 1 minor fix, 3 major enhancements
|
3
|
+
* fixed warnings about using XML::Parser (mojodna)
|
4
|
+
* Improved namespace support, now handles multiple namespaces and allows namespaces to be set item wide or on a per element basis (mojodna)
|
5
|
+
* Auto detect root nodes (mojodna)
|
6
|
+
* Type coercion (mojodna)
|
7
|
+
|
1
8
|
== 0.2.0
|
2
9
|
* 1 major enhancement, 2 minor ehancements
|
3
10
|
* Automatic handling of namespaces (part by Robert Lowrey and rest by John Nunemaker)
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ Echoe.new(ProjectName, HappyMapper::Version) do |p|
|
|
13
13
|
p.url = "http://#{ProjectName}.rubyforge.org"
|
14
14
|
p.author = "John Nunemaker"
|
15
15
|
p.email = "nunemaker@gmail.com"
|
16
|
-
p.extra_deps = [['libxml-ruby', '
|
16
|
+
p.extra_deps = [['libxml-ruby', '= 0.9.8']]
|
17
17
|
p.need_tar_gz = false
|
18
18
|
p.docs_host = WebsitePath
|
19
19
|
end
|
data/TODO
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
* doesn't do xml namespaces really (does work with default namespace though)
|
data/examples/amazon.rb
CHANGED
@@ -3,6 +3,8 @@ require File.join(dir, 'happymapper')
|
|
3
3
|
|
4
4
|
file_contents = File.read(dir + '/../spec/fixtures/pita.xml')
|
5
5
|
|
6
|
+
# The document `pita.xml` contains both a default namespace and the 'georss'
|
7
|
+
# namespace (for the 'point' element).
|
6
8
|
module PITA
|
7
9
|
class Item
|
8
10
|
include HappyMapper
|
@@ -11,6 +13,9 @@ module PITA
|
|
11
13
|
element :asin, String, :tag => 'ASIN'
|
12
14
|
element :detail_page_url, String, :tag => 'DetailPageURL'
|
13
15
|
element :manufacturer, String, :tag => 'Manufacturer', :deep => true
|
16
|
+
# this is the only element that exists in a different namespace, so it
|
17
|
+
# must be explicitly specified
|
18
|
+
element :point, String, :tag => 'point', :namespace => 'georss'
|
14
19
|
end
|
15
20
|
|
16
21
|
class Items
|
data/examples/current_weather.rb
CHANGED
@@ -5,7 +5,9 @@ file_contents = File.read(dir + '/../spec/fixtures/current_weather.xml')
|
|
5
5
|
|
6
6
|
class CurrentWeather
|
7
7
|
include HappyMapper
|
8
|
+
|
8
9
|
tag 'ob'
|
10
|
+
namespace 'aws'
|
9
11
|
element :temperature, Integer, :tag => 'temp'
|
10
12
|
element :feels_like, Integer, :tag => 'feels-like'
|
11
13
|
element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
|
data/examples/dashed_elements.rb
CHANGED
data/happymapper.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{happymapper}
|
5
|
-
s.version = "0.2.
|
5
|
+
s.version = "0.2.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["John Nunemaker"]
|
@@ -25,14 +25,14 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.specification_version = 2
|
26
26
|
|
27
27
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
-
s.add_runtime_dependency(%q<libxml-ruby>, ["
|
28
|
+
s.add_runtime_dependency(%q<libxml-ruby>, ["= 0.9.8"])
|
29
29
|
s.add_development_dependency(%q<echoe>, [">= 0"])
|
30
30
|
else
|
31
|
-
s.add_dependency(%q<libxml-ruby>, ["
|
31
|
+
s.add_dependency(%q<libxml-ruby>, ["= 0.9.8"])
|
32
32
|
s.add_dependency(%q<echoe>, [">= 0"])
|
33
33
|
end
|
34
34
|
else
|
35
|
-
s.add_dependency(%q<libxml-ruby>, ["
|
35
|
+
s.add_dependency(%q<libxml-ruby>, ["= 0.9.8"])
|
36
36
|
s.add_dependency(%q<echoe>, [">= 0"])
|
37
37
|
end
|
38
38
|
end
|
data/lib/happymapper.rb
CHANGED
@@ -5,7 +5,7 @@ require 'date'
|
|
5
5
|
require 'time'
|
6
6
|
require 'rubygems'
|
7
7
|
|
8
|
-
gem 'libxml-ruby', '
|
8
|
+
gem 'libxml-ruby', '= 0.9.8'
|
9
9
|
require 'xml'
|
10
10
|
require 'libxml_ext/libxml_helper'
|
11
11
|
|
@@ -13,7 +13,9 @@ require 'libxml_ext/libxml_helper'
|
|
13
13
|
class Boolean; end
|
14
14
|
|
15
15
|
module HappyMapper
|
16
|
-
|
16
|
+
|
17
|
+
DEFAULT_NS = "happymapper"
|
18
|
+
|
17
19
|
def self.included(base)
|
18
20
|
base.instance_variable_set("@attributes", {})
|
19
21
|
base.instance_variable_set("@elements", {})
|
@@ -50,12 +52,16 @@ module HappyMapper
|
|
50
52
|
def has_many(name, type, options={})
|
51
53
|
element name, type, {:single => false}.merge(options)
|
52
54
|
end
|
53
|
-
|
54
|
-
#
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
@
|
55
|
+
|
56
|
+
# Specify a namespace if a node and all its children are all namespaced
|
57
|
+
# elements. This is simpler than passing the :namespace option to each
|
58
|
+
# defined element.
|
59
|
+
def namespace(namespace = nil)
|
60
|
+
@namespace = namespace if namespace
|
61
|
+
@namespace
|
62
|
+
end
|
63
|
+
|
64
|
+
def tag(new_tag_name)
|
59
65
|
@tag_name = new_tag_name.to_s
|
60
66
|
end
|
61
67
|
|
@@ -65,55 +71,61 @@ module HappyMapper
|
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
node.
|
82
|
-
# warn "Default XML namespace present -- results are unpredictable"
|
74
|
+
def parse(xml, options = {})
|
75
|
+
# locally scoped copy of namespace for this parse run
|
76
|
+
namespace = @namespace
|
77
|
+
|
78
|
+
if xml.is_a?(XML::Node)
|
79
|
+
node = xml
|
80
|
+
else
|
81
|
+
if xml.is_a?(XML::Document)
|
82
|
+
node = xml.root
|
83
|
+
else
|
84
|
+
node = xml.to_libxml_doc.root
|
85
|
+
end
|
86
|
+
|
87
|
+
root = node.name == get_tag_name
|
83
88
|
end
|
84
|
-
|
85
|
-
|
86
|
-
|
89
|
+
|
90
|
+
# This is the entry point into the parsing pipeline, so the default
|
91
|
+
# namespace prefix registered here will propagate down
|
92
|
+
namespaces = node.namespaces
|
93
|
+
if namespaces && namespaces.default
|
94
|
+
namespaces.default_prefix = DEFAULT_NS
|
95
|
+
namespace ||= DEFAULT_NS
|
87
96
|
end
|
88
|
-
|
89
|
-
|
90
|
-
xpath +=
|
91
|
-
xpath += namespace if namespace
|
97
|
+
|
98
|
+
xpath = root ? '/' : './/'
|
99
|
+
xpath += "#{namespace}:" if namespace
|
92
100
|
xpath += get_tag_name
|
93
101
|
# puts "parse: #{xpath}"
|
94
102
|
|
95
103
|
nodes = node.find(xpath)
|
96
|
-
nodes.
|
104
|
+
collection = nodes.collect do |n|
|
97
105
|
obj = new
|
98
106
|
|
99
107
|
attributes.each do |attr|
|
100
108
|
obj.send("#{attr.method_name}=",
|
101
|
-
attr.from_xml_node(n))
|
109
|
+
attr.from_xml_node(n, namespace))
|
102
110
|
end
|
103
111
|
|
104
112
|
elements.each do |elem|
|
105
|
-
elem.namespace = namespace
|
106
113
|
obj.send("#{elem.method_name}=",
|
107
|
-
elem.from_xml_node(n))
|
114
|
+
elem.from_xml_node(n, namespace))
|
108
115
|
end
|
109
|
-
|
116
|
+
|
117
|
+
obj
|
110
118
|
end
|
111
119
|
|
112
120
|
# per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354
|
113
121
|
nodes = nil
|
114
122
|
GC.start
|
115
123
|
|
116
|
-
options[:single] ||
|
124
|
+
if options[:single] || root
|
125
|
+
collection.first
|
126
|
+
else
|
127
|
+
collection
|
128
|
+
end
|
117
129
|
end
|
118
130
|
end
|
119
131
|
end
|
data/lib/happymapper/item.rb
CHANGED
@@ -7,33 +7,55 @@ module HappyMapper
|
|
7
7
|
# options:
|
8
8
|
# :deep => Boolean False to only parse element's children, True to include
|
9
9
|
# grandchildren and all others down the chain (// in expath)
|
10
|
+
# :namespace => String Element's namespace if it's not the global or inherited
|
11
|
+
# default
|
12
|
+
# :parser => Symbol Class method to use for type coercion.
|
13
|
+
# :raw => Boolean Use raw node value (inc. tags) when parsing.
|
10
14
|
# :single => Boolean False if object should be collection, True for single object
|
15
|
+
# :tag => String Element name if it doesn't match the specified name.
|
11
16
|
def initialize(name, type, o={})
|
12
17
|
self.name = name.to_s
|
13
18
|
self.type = type
|
14
19
|
self.tag = o.delete(:tag) || name.to_s
|
15
|
-
self.options =
|
16
|
-
:single => false,
|
17
|
-
:deep => false,
|
18
|
-
}.merge(o)
|
20
|
+
self.options = o
|
19
21
|
|
20
22
|
@xml_type = self.class.to_s.split('::').last.downcase
|
21
23
|
end
|
22
24
|
|
23
|
-
def from_xml_node(node)
|
25
|
+
def from_xml_node(node, namespace)
|
24
26
|
if primitive?
|
25
|
-
|
26
|
-
|
27
|
+
find(node, namespace) do |n|
|
28
|
+
if n.respond_to?(:content)
|
29
|
+
typecast(n.content)
|
30
|
+
else
|
31
|
+
typecast(n.to_s)
|
32
|
+
end
|
27
33
|
end
|
28
34
|
else
|
29
|
-
|
35
|
+
if options[:parser]
|
36
|
+
find(node, namespace) do |n|
|
37
|
+
if n.respond_to?(:content) && !options[:raw]
|
38
|
+
value = n.content
|
39
|
+
else
|
40
|
+
value = n.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
begin
|
44
|
+
type.send(options[:parser].to_sym, value)
|
45
|
+
rescue
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
type.parse(node, options)
|
51
|
+
end
|
30
52
|
end
|
31
53
|
end
|
32
54
|
|
33
|
-
def xpath
|
55
|
+
def xpath(namespace = self.namespace)
|
34
56
|
xpath = ''
|
35
57
|
xpath += './/' if options[:deep]
|
36
|
-
xpath += namespace if namespace
|
58
|
+
xpath += "#{namespace}:" if namespace
|
37
59
|
xpath += tag
|
38
60
|
# puts "xpath: #{xpath}"
|
39
61
|
xpath
|
@@ -86,16 +108,25 @@ module HappyMapper
|
|
86
108
|
end
|
87
109
|
|
88
110
|
private
|
89
|
-
def
|
111
|
+
def find(node, namespace, &block)
|
112
|
+
# this node has a custom namespace (that is present in the doc)
|
113
|
+
if self.namespace && node.namespaces.find_by_prefix(self.namespace)
|
114
|
+
# from the class definition
|
115
|
+
namespace = self.namespace
|
116
|
+
elsif options[:namespace] && node.namespaces.find_by_prefix(options[:namespace])
|
117
|
+
# from an element definition
|
118
|
+
namespace = options[:namespace]
|
119
|
+
end
|
120
|
+
|
90
121
|
if element?
|
91
|
-
result = node.find_first(xpath)
|
122
|
+
result = node.find_first(xpath(namespace))
|
92
123
|
# puts "vfxn: #{xpath} #{result.inspect}"
|
93
124
|
if result
|
94
|
-
value = yield(result
|
125
|
+
value = yield(result)
|
95
126
|
if options[:attributes].is_a?(Hash)
|
96
127
|
result.attributes.each do |xml_attribute|
|
97
128
|
if attribute_options = options[:attributes][xml_attribute.name.to_sym]
|
98
|
-
attribute_value = Attribute.new(xml_attribute.name.to_sym, *attribute_options).from_xml_node(result)
|
129
|
+
attribute_value = Attribute.new(xml_attribute.name.to_sym, *attribute_options).from_xml_node(result, namespace)
|
99
130
|
result.instance_eval <<-EOV
|
100
131
|
def value.#{xml_attribute.name}
|
101
132
|
#{attribute_value.inspect}
|
data/lib/happymapper/version.rb
CHANGED
data/spec/fixtures/pita.xml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
|
2
|
+
<ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05" xmlns:georss="http://www.georss.org/georss">
|
3
3
|
<OperationRequest>
|
4
4
|
<HTTPHeaders>
|
5
5
|
<Header Name="UserAgent">
|
@@ -27,6 +27,7 @@
|
|
27
27
|
<TotalPages>3</TotalPages>
|
28
28
|
<Item>
|
29
29
|
<ASIN>0321480791</ASIN>
|
30
|
+
<georss:point>38.5351715088 -121.7948684692</georss:point>
|
30
31
|
<DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
|
31
32
|
<ItemAttributes>
|
32
33
|
<Author>Michael Hartl</Author>
|
data/spec/happymapper_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
require 'pp'
|
3
|
+
require 'uri'
|
3
4
|
|
4
5
|
class Feature
|
5
6
|
include HappyMapper
|
@@ -38,7 +39,7 @@ module FamilySearch
|
|
38
39
|
class FamilyTree
|
39
40
|
include HappyMapper
|
40
41
|
|
41
|
-
tag 'familytree'
|
42
|
+
tag 'familytree'
|
42
43
|
attribute :version, String
|
43
44
|
attribute :status_message, String, :tag => 'statusMessage'
|
44
45
|
attribute :status_code, String, :tag => 'statusCode'
|
@@ -51,6 +52,7 @@ module FedEx
|
|
51
52
|
include HappyMapper
|
52
53
|
|
53
54
|
tag 'Address'
|
55
|
+
namespace 'v2'
|
54
56
|
element :city, String, :tag => 'City'
|
55
57
|
element :state, String, :tag => 'StateOrProvinceCode'
|
56
58
|
element :zip, String, :tag => 'PostalCode'
|
@@ -62,6 +64,7 @@ module FedEx
|
|
62
64
|
include HappyMapper
|
63
65
|
|
64
66
|
tag 'Events'
|
67
|
+
namespace 'v2'
|
65
68
|
element :timestamp, String, :tag => 'Timestamp'
|
66
69
|
element :eventtype, String, :tag => 'EventType'
|
67
70
|
element :eventdescription, String, :tag => 'EventDescription'
|
@@ -72,6 +75,7 @@ module FedEx
|
|
72
75
|
include HappyMapper
|
73
76
|
|
74
77
|
tag 'PackageWeight'
|
78
|
+
namespace 'v2'
|
75
79
|
element :units, String, :tag => 'Units'
|
76
80
|
element :value, Integer, :tag => 'Value'
|
77
81
|
end
|
@@ -80,6 +84,7 @@ module FedEx
|
|
80
84
|
include HappyMapper
|
81
85
|
|
82
86
|
tag 'TrackDetails'
|
87
|
+
namespace 'v2'
|
83
88
|
element :tracking_number, String, :tag => 'TrackingNumber'
|
84
89
|
element :status_code, String, :tag => 'StatusCode'
|
85
90
|
element :status_desc, String, :tag => 'StatusDescription'
|
@@ -94,6 +99,7 @@ module FedEx
|
|
94
99
|
include HappyMapper
|
95
100
|
|
96
101
|
tag 'Notifications'
|
102
|
+
namespace 'v2'
|
97
103
|
element :severity, String, :tag => 'Severity'
|
98
104
|
element :source, String, :tag => 'Source'
|
99
105
|
element :code, Integer, :tag => 'Code'
|
@@ -105,13 +111,15 @@ module FedEx
|
|
105
111
|
include HappyMapper
|
106
112
|
|
107
113
|
tag 'TransactionDetail'
|
114
|
+
namespace 'v2'
|
108
115
|
element :cust_tran_id, String, :tag => 'CustomerTransactionId'
|
109
116
|
end
|
110
117
|
|
111
118
|
class TrackReply
|
112
119
|
include HappyMapper
|
113
120
|
|
114
|
-
tag 'TrackReply'
|
121
|
+
tag 'TrackReply'
|
122
|
+
namespace 'v2'
|
115
123
|
element :highest_severity, String, :tag => 'HighestSeverity'
|
116
124
|
element :more_data, Boolean, :tag => 'MoreData'
|
117
125
|
has_many :notifications, Notification, :tag => 'Notifications'
|
@@ -167,6 +175,7 @@ class Status
|
|
167
175
|
element :in_reply_to_status_id, Integer
|
168
176
|
element :in_reply_to_user_id, Integer
|
169
177
|
element :favorited, Boolean
|
178
|
+
element :non_existent, String, :tag => 'dummy', :namespace => 'fake'
|
170
179
|
has_one :user, User
|
171
180
|
end
|
172
181
|
|
@@ -174,6 +183,7 @@ class CurrentWeather
|
|
174
183
|
include HappyMapper
|
175
184
|
|
176
185
|
tag 'ob'
|
186
|
+
namespace 'aws'
|
177
187
|
element :temperature, Integer, :tag => 'temp'
|
178
188
|
element :feels_like, Integer, :tag => 'feels-like'
|
179
189
|
element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
|
@@ -182,7 +192,7 @@ end
|
|
182
192
|
class Address
|
183
193
|
include HappyMapper
|
184
194
|
|
185
|
-
tag 'address'
|
195
|
+
tag 'address'
|
186
196
|
element :street, String
|
187
197
|
element :postcode, String
|
188
198
|
element :housenumber, String
|
@@ -190,14 +200,19 @@ class Address
|
|
190
200
|
element :country, String
|
191
201
|
end
|
192
202
|
|
203
|
+
# for type coercion
|
204
|
+
class ProductGroup < String; end
|
205
|
+
|
193
206
|
module PITA
|
194
207
|
class Item
|
195
208
|
include HappyMapper
|
196
209
|
|
197
210
|
tag 'Item' # if you put class in module you need tag
|
198
211
|
element :asin, String, :tag => 'ASIN'
|
199
|
-
element :detail_page_url,
|
212
|
+
element :detail_page_url, URI, :tag => 'DetailPageURL', :parser => :parse
|
200
213
|
element :manufacturer, String, :tag => 'Manufacturer', :deep => true
|
214
|
+
element :point, String, :tag => 'point', :namespace => 'georss'
|
215
|
+
element :product_group, ProductGroup, :tag => 'ProductGroup', :deep => true, :parser => :new, :raw => true
|
201
216
|
end
|
202
217
|
|
203
218
|
class Items
|
@@ -214,7 +229,7 @@ module GitHub
|
|
214
229
|
class Commit
|
215
230
|
include HappyMapper
|
216
231
|
|
217
|
-
tag "commit"
|
232
|
+
tag "commit"
|
218
233
|
element :url, String
|
219
234
|
element :tree, String
|
220
235
|
element :message, String
|
@@ -290,7 +305,7 @@ describe HappyMapper do
|
|
290
305
|
element.type.should == User
|
291
306
|
element.options[:single] = false
|
292
307
|
end
|
293
|
-
|
308
|
+
|
294
309
|
it "should default tag name to lowercase class" do
|
295
310
|
Foo.get_tag_name.should == 'foo'
|
296
311
|
end
|
@@ -305,6 +320,11 @@ describe HappyMapper do
|
|
305
320
|
Foo.get_tag_name.should == 'FooBar'
|
306
321
|
end
|
307
322
|
|
323
|
+
it "should allow setting a namespace" do
|
324
|
+
Foo.namespace(namespace = "foo")
|
325
|
+
Foo.namespace.should == namespace
|
326
|
+
end
|
327
|
+
|
308
328
|
it "should provide #parse" do
|
309
329
|
Foo.should respond_to(:parse)
|
310
330
|
end
|
@@ -320,7 +340,7 @@ describe HappyMapper do
|
|
320
340
|
describe "#elements" do
|
321
341
|
it "should only return elements for the current class" do
|
322
342
|
Post.elements.size.should == 0
|
323
|
-
Status.elements.size.should ==
|
343
|
+
Status.elements.size.should == 10
|
324
344
|
end
|
325
345
|
end
|
326
346
|
|
@@ -376,8 +396,11 @@ describe HappyMapper do
|
|
376
396
|
first = items.items[0]
|
377
397
|
second = items.items[1]
|
378
398
|
first.asin.should == '0321480791'
|
379
|
-
first.
|
399
|
+
first.point.should == '38.5351715088 -121.7948684692'
|
400
|
+
first.detail_page_url.should be_a_kind_of(URI)
|
401
|
+
first.detail_page_url.to_s.should == 'http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh'
|
380
402
|
first.manufacturer.should == 'Addison-Wesley Professional'
|
403
|
+
first.product_group.should == '<ProductGroup>Book</ProductGroup>'
|
381
404
|
second.asin.should == '047022388X'
|
382
405
|
second.manufacturer.should == 'Wrox'
|
383
406
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jnunemaker-happymapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
@@ -17,9 +17,9 @@ dependencies:
|
|
17
17
|
version_requirement:
|
18
18
|
version_requirements: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
|
-
- - "
|
20
|
+
- - "="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.9.
|
22
|
+
version: 0.9.8
|
23
23
|
version:
|
24
24
|
- !ruby/object:Gem::Dependency
|
25
25
|
name: echoe
|