smg 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +6 -62
- data/examples/discogs/label.rb +62 -0
- data/examples/discogs/search.rb +60 -0
- data/examples/plant.rb +1 -2
- data/examples/twitter.rb +8 -5
- data/examples/weather.rb +146 -0
- data/lib/smg.rb +4 -0
- data/lib/smg/document.rb +25 -8
- data/lib/smg/http.rb +66 -0
- data/lib/smg/http/exceptions.rb +37 -0
- data/lib/smg/http/request.rb +126 -0
- data/lib/smg/mapping.rb +11 -1
- data/lib/smg/mapping/element.rb +29 -13
- data/lib/smg/mapping/typecasts.rb +2 -1
- data/lib/smg/model.rb +9 -3
- data/lib/smg/resource.rb +5 -1
- data/spec/collect_spec.rb +254 -0
- data/spec/context_spec.rb +189 -0
- data/spec/extract_spec.rb +200 -0
- data/spec/filtering_spec.rb +164 -0
- data/spec/fixtures/discogs/948224.xml +1 -0
- data/spec/fixtures/discogs/Enzyme+Records.xml +9 -0
- data/spec/fixtures/discogs/Genosha+Recordings.xml +13 -0
- data/spec/fixtures/discogs/Ophidian.xml +6 -0
- data/spec/fixtures/fake/malus.xml +18 -0
- data/spec/fixtures/fake/valve.xml +8 -0
- data/spec/fixtures/twitter/pipopolam.xml +46 -0
- data/spec/fixtures/yahoo.weather.com.xml +50 -0
- data/spec/http/request_spec.rb +186 -0
- data/spec/http/shared/automatic.rb +43 -0
- data/spec/http/shared/non_automatic.rb +36 -0
- data/spec/http/shared/redirectable.rb +30 -0
- data/spec/http_spec.rb +76 -0
- data/spec/lib/helpers/http_helpers.rb +27 -0
- data/spec/lib/matchers/instance_methods.rb +38 -0
- data/spec/mapping/element_spec.rb +241 -0
- data/spec/mapping/typecasts_spec.rb +52 -0
- data/spec/resource_spec.rb +30 -0
- data/spec/root_spec.rb +26 -0
- data/spec/spec_helper.rb +23 -0
- metadata +53 -10
- data/examples/discogs.rb +0 -39
data/spec/http_spec.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.expand_path File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe SMG::HTTP::Model, ".uri_for" do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@klass = Class.new { include SMG::Resource, SMG::HTTP }
|
7
|
+
@klass.site "http://www.example.org"
|
8
|
+
@klass.params "developer" => "Valve"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "appends a path to the base URI" do
|
12
|
+
uri = @klass.send(:uri_for, "search")
|
13
|
+
uri.host.should == "www.example.org"
|
14
|
+
uri.path.should == "/search"
|
15
|
+
uri.query_values.should == {"developer" => "Valve"}
|
16
|
+
end
|
17
|
+
|
18
|
+
it "appends a query to the base URI" do
|
19
|
+
uri = @klass.send(:uri_for, "search", {"cake" => "Lie"})
|
20
|
+
uri.host.should == "www.example.org"
|
21
|
+
uri.path.should == "/search"
|
22
|
+
uri.query_values.should == {"developer" => "Valve", "cake" => "Lie"}
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe SMG::HTTP::Model do
|
28
|
+
|
29
|
+
before :all do
|
30
|
+
@klass = Class.new { include SMG::Resource, SMG::HTTP }
|
31
|
+
@klass.site "http://www.example.org"
|
32
|
+
@klass.params "developer" => "Valve"
|
33
|
+
@klass.extract "game/name"
|
34
|
+
end
|
35
|
+
|
36
|
+
Hash[[:get, :post, :put, :delete, :head].zip(SMG::HTTP::Request::VERBS)].each do |sym,verb|
|
37
|
+
describe ".#{sym}" do
|
38
|
+
|
39
|
+
before :each do
|
40
|
+
@response = Net::HTTPOK.new('1.1', 200, "OK")
|
41
|
+
@response.stub!(:body).and_return("<game><name>Portal</name></game>")
|
42
|
+
end
|
43
|
+
|
44
|
+
before :each do
|
45
|
+
@request = mock('request')
|
46
|
+
@request.stub!(:perform).and_return(@response)
|
47
|
+
end
|
48
|
+
|
49
|
+
before :each do
|
50
|
+
@headers = {"Accept-Encoding" => "gzip,deflate;*;q=0"}
|
51
|
+
@options = {:query => {"cake" => "LIE"}, :headers => @headers}
|
52
|
+
SMG::HTTP::Request.should_receive(:new).
|
53
|
+
with(verb, instance_of(Addressable::URI), {:headers => @headers}).
|
54
|
+
and_return(@request)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "performs #{sym.to_s.upcase} request" do
|
58
|
+
@klass.send(sym, "game", @options)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "parses response' body when no block given" do
|
62
|
+
@game = @klass.send(sym, "game", @options)
|
63
|
+
@game.name.should == "Portal"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "yields response and parses the block returning value when block given" do
|
67
|
+
@game = @klass.send(sym, "game", @options) { |response| "<game><name>Portal2</name></game>" }
|
68
|
+
@game.name.should == "Portal2"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
# EOF
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Spec #:nodoc:
|
2
|
+
module Helpers #:nodoc:
|
3
|
+
module HTTPHelpers
|
4
|
+
|
5
|
+
def http(uri, proxy = nil)
|
6
|
+
@http ||= mock('http')
|
7
|
+
uri = Addressable::URI.parse(uri)
|
8
|
+
args = (proxy && p = Addressable::URI.parse(proxy)) ?
|
9
|
+
[uri.host, uri.port, p.host, p.port, p.user, p.password] :
|
10
|
+
[uri.host, uri.port]
|
11
|
+
|
12
|
+
Net::HTTP.should_receive(:new).with(*args).and_return(@http)
|
13
|
+
end
|
14
|
+
|
15
|
+
def stub_response(code, message, *args)
|
16
|
+
response = Net::HTTPResponse::CODE_TO_OBJ[code.to_s].new('1.1', code, message)
|
17
|
+
response.initialize_http_header(Hash === args.last ? args.pop : {})
|
18
|
+
response.stub!(:body).and_return(args.join) unless args.empty?
|
19
|
+
@http.should_receive(:request).and_return response
|
20
|
+
response
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# EOF
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Spec #:nodoc:
|
2
|
+
module Matchers #:nodoc:
|
3
|
+
|
4
|
+
#http://github.com/rubyspec/mspec/blob/master/lib/mspec/matchers/have_instance_method.rb
|
5
|
+
class HaveInstanceMethodMatcher
|
6
|
+
|
7
|
+
def initialize(method, include_super)
|
8
|
+
@method = method.to_sym
|
9
|
+
@include_super = include_super
|
10
|
+
end
|
11
|
+
|
12
|
+
def matches?(mod)
|
13
|
+
@mod = mod
|
14
|
+
mod.instance_methods(@include_super).include?(@method) ||
|
15
|
+
mod.instance_methods(@include_super).include?(@method.to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_message
|
19
|
+
["Expected #{@mod} to have instance method '#{@method.to_s}'",
|
20
|
+
"but it does not"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def negative_failure_message
|
24
|
+
["Expected #{@mod} NOT to have instance method '#{@method.to_s}'",
|
25
|
+
"but it does"]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module HaveInstanceMethodMixin
|
30
|
+
def have_instance_method(method, include_super=true)
|
31
|
+
HaveInstanceMethodMatcher.new method, include_super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# EOF
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require File.expand_path File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe SMG::Mapping::Element do
|
4
|
+
|
5
|
+
describe "#initialize" do
|
6
|
+
|
7
|
+
it "respects path" do
|
8
|
+
e = SMG::Mapping::Element.new(['node','subnode'])
|
9
|
+
e.name.should == :subnode
|
10
|
+
e.accessor.should == :subnode=
|
11
|
+
|
12
|
+
e = SMG::Mapping::Element.new(['node','ns:subnode'])
|
13
|
+
e.name.should == :ns_subnode
|
14
|
+
e.accessor.should == :ns_subnode=
|
15
|
+
|
16
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :nested => true)
|
17
|
+
e.name.should == :subnode
|
18
|
+
e.accessor.should == :subnode=
|
19
|
+
|
20
|
+
e = SMG::Mapping::Element.new(['node','ns:subnode'], :nested => true)
|
21
|
+
e.name.should == :ns_subnode
|
22
|
+
e.accessor.should == :ns_subnode=
|
23
|
+
end
|
24
|
+
|
25
|
+
it "respects namespaces" do
|
26
|
+
end
|
27
|
+
|
28
|
+
it "respects :at option" do
|
29
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :at => :something)
|
30
|
+
e.name.should == :something
|
31
|
+
e.accessor.should == :something=
|
32
|
+
|
33
|
+
e = SMG::Mapping::Element.new(['node','ns:subnode'], :at => :something)
|
34
|
+
e.name.should == :something
|
35
|
+
e.accessor.should == :something=
|
36
|
+
|
37
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :at => :something, :nested => true)
|
38
|
+
e.name.should == :something
|
39
|
+
e.accessor.should == :something=
|
40
|
+
|
41
|
+
e = SMG::Mapping::Element.new(['node','ns:subnode'], :at => :something, :nested => true)
|
42
|
+
e.name.should == :something
|
43
|
+
e.accessor.should == :something=
|
44
|
+
end
|
45
|
+
|
46
|
+
it "respects :as option" do
|
47
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :at => :whatever, :as => :something)
|
48
|
+
e.name.should == :something
|
49
|
+
e.accessor.should == :something=
|
50
|
+
|
51
|
+
e = SMG::Mapping::Element.new(['node','ns:subnode'], :at => :whatever, :as => :something)
|
52
|
+
e.name.should == :something
|
53
|
+
e.accessor.should == :something=
|
54
|
+
|
55
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :as => :whatever, :nested => true)
|
56
|
+
e.name.should == :whatever
|
57
|
+
e.accessor.should == :whatever=
|
58
|
+
|
59
|
+
e = SMG::Mapping::Element.new(['node','ns:subnode'], :as => :whatever, :nested => true)
|
60
|
+
e.name.should == :whatever
|
61
|
+
e.accessor.should == :whatever=
|
62
|
+
end
|
63
|
+
|
64
|
+
it "respects :collection option" do
|
65
|
+
e = SMG::Mapping::Element.new(['node','subnodes'], :collection => true)
|
66
|
+
e.name.should == :subnodes
|
67
|
+
e.accessor.should == :append_to_subnodes
|
68
|
+
|
69
|
+
e = SMG::Mapping::Element.new(['node','ns:subnodes'], :collection => true)
|
70
|
+
e.name.should == :ns_subnodes
|
71
|
+
e.accessor.should == :append_to_ns_subnodes
|
72
|
+
|
73
|
+
e = SMG::Mapping::Element.new(['node','subnodes'], :at => :something, :collection => true)
|
74
|
+
e.name.should == :something
|
75
|
+
e.accessor.should == :append_to_something
|
76
|
+
|
77
|
+
e = SMG::Mapping::Element.new(['node','ns:subnodes'], :at => :something, :collection => true)
|
78
|
+
e.name.should == :something
|
79
|
+
e.accessor.should == :append_to_something
|
80
|
+
|
81
|
+
e = SMG::Mapping::Element.new(['node','subnodes'], :at => :whatever, :as => :something, :collection => true)
|
82
|
+
e.name.should == :something
|
83
|
+
e.accessor.should == :append_to_something
|
84
|
+
|
85
|
+
e = SMG::Mapping::Element.new(['node','ns:subnodes'], :at => :whatever, :as => :something, :collection => true)
|
86
|
+
e.name.should == :something
|
87
|
+
e.accessor.should == :append_to_something
|
88
|
+
|
89
|
+
e = SMG::Mapping::Element.new(['node','subnodes'], :as => :something, :collection => true)
|
90
|
+
e.name.should == :something
|
91
|
+
e.accessor.should == :append_to_something
|
92
|
+
|
93
|
+
e = SMG::Mapping::Element.new(['node','ns:subnodes'], :as => :something, :collection => true)
|
94
|
+
e.name.should == :something
|
95
|
+
e.accessor.should == :append_to_something
|
96
|
+
end
|
97
|
+
|
98
|
+
it "defaults @context to nil" do
|
99
|
+
e = SMG::Mapping::Element.new(['node','subnode'])
|
100
|
+
e.context.should be_nil
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "with :class option" do
|
104
|
+
|
105
|
+
it "defines the @data_class if :class is an SMG::Model" do
|
106
|
+
klass = Class.new { include SMG::Resource }
|
107
|
+
e = SMG::Mapping::Element.new(['node'], :class => klass)
|
108
|
+
e.data_class.should == klass
|
109
|
+
end
|
110
|
+
|
111
|
+
it "defines the @cast_to if :class is a valid typecast" do
|
112
|
+
klass = Class.new { include SMG::Resource }
|
113
|
+
e = SMG::Mapping::Element.new(['node'], :class => :string)
|
114
|
+
e.cast_to.should == :string
|
115
|
+
end
|
116
|
+
|
117
|
+
it "raises an ArgumentError otherwise" do
|
118
|
+
lambda { SMG::Mapping::Element.new(['node'], :class => "bogus!")}.
|
119
|
+
should raise_error ArgumentError, %r{should be an SMG::Model or a valid typecast}
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "with :context option" do
|
125
|
+
|
126
|
+
it "defaults @context to nil, if :context is an empty Array" do
|
127
|
+
e = SMG::Mapping::Element.new(['node'], :context => [])
|
128
|
+
e.context.should be_nil
|
129
|
+
end
|
130
|
+
|
131
|
+
it "removes duplicates from @context" do
|
132
|
+
|
133
|
+
e = SMG::Mapping::Element.new(['node'], :context => [:foo, :bar, :baz])
|
134
|
+
e.context.should == [:foo, :bar, :baz]
|
135
|
+
|
136
|
+
e = SMG::Mapping::Element.new(['node'], :context => [:foo, :bar, :foo, :bar, :baz, :baz])
|
137
|
+
e.context.should == [:foo, :bar, :baz]
|
138
|
+
|
139
|
+
# undestructive
|
140
|
+
cct = [:foo, :foo, :bar]
|
141
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :context => cct)
|
142
|
+
cct.should == [:foo, :foo, :bar]
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
it "raises an ArgumentError, if :context is not an Array of Symbols" do
|
147
|
+
lambda { e = SMG::Mapping::Element.new(['node'], :context => "something") }.
|
148
|
+
should raise_error ArgumentError, %r{should be an Array of Symbols}
|
149
|
+
|
150
|
+
lambda { e = SMG::Mapping::Element.new(['node'], :context => [42]) }.
|
151
|
+
should raise_error ArgumentError, %r{should be an Array of Symbols}
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "#collection?" do
|
159
|
+
|
160
|
+
it "returns true if Element is a collection" do
|
161
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :collection => true)
|
162
|
+
e.should be_a_collection
|
163
|
+
end
|
164
|
+
|
165
|
+
it "returns false otherwise" do
|
166
|
+
e = SMG::Mapping::Element.new(['node','subnode'])
|
167
|
+
e.should_not be_a_collection
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "#cast" do
|
173
|
+
|
174
|
+
it "does nothing if there's no @cast_to" do
|
175
|
+
e = SMG::Mapping::Element.new(['node'])
|
176
|
+
thing = "42"
|
177
|
+
e.cast(thing).should be_eql thing
|
178
|
+
end
|
179
|
+
|
180
|
+
it "performs the typecast otherwise" do
|
181
|
+
e = SMG::Mapping::Element.new(['node'], :class => :integer)
|
182
|
+
thing = "42"
|
183
|
+
SMG::Mapping::TypeCasts.should_receive(:[]).with(:integer, thing).and_return("42 (typecasted)")
|
184
|
+
e.cast(thing).should == "42 (typecasted)"
|
185
|
+
end
|
186
|
+
|
187
|
+
it "raises an ArgumentError if typecasting fails" do
|
188
|
+
e = SMG::Mapping::Element.new(['node'], :class => :datetime)
|
189
|
+
lambda { e.cast('42') }.
|
190
|
+
should raise_error ArgumentError, %r{"42" is not a valid source for :datetime}
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
describe "#in_context_of?" do
|
196
|
+
|
197
|
+
it "returns true if @context of an Element is a nil" do
|
198
|
+
e = SMG::Mapping::Element.new(['node','subnode'])
|
199
|
+
e.context.should == nil
|
200
|
+
e.in_context_of?(:whatever).should == true
|
201
|
+
end
|
202
|
+
|
203
|
+
it "returns true if @context of an Element includes context" do
|
204
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :context => [:foo])
|
205
|
+
e.context.should == [:foo]
|
206
|
+
e.in_context_of?(:foo).should == true
|
207
|
+
end
|
208
|
+
|
209
|
+
it "returns false otherwise" do
|
210
|
+
e = SMG::Mapping::Element.new(['node','subnode'], :context => [:foo])
|
211
|
+
e.context.should == [:foo]
|
212
|
+
e.in_context_of?(:bar).should == false
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "#with?" do
|
218
|
+
|
219
|
+
it "returns true if the Hash passed contains @with" do
|
220
|
+
e = SMG::Mapping::Element.new(['node'], :with => {"id" => "3", "status" => "accepted"})
|
221
|
+
e.should be_with("id" => "3", "status" => "accepted")
|
222
|
+
e.should be_with("id" => "3", "status" => "accepted", "key" => "value")
|
223
|
+
end
|
224
|
+
|
225
|
+
it "returns true if there are no @with conditions" do
|
226
|
+
e = SMG::Mapping::Element.new(['node','subnode'])
|
227
|
+
e.with.should == nil
|
228
|
+
e.should be_with("key" => "value")
|
229
|
+
end
|
230
|
+
|
231
|
+
it "returns false otherwise" do
|
232
|
+
e = SMG::Mapping::Element.new(['node'], :with => {"id" => "3", "status" => "accepted"})
|
233
|
+
e.should_not be_with("status" => "accepted")
|
234
|
+
e.should_not be_with({})
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
# EOF
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe SMG::Mapping::TypeCasts, "[]" do
|
4
|
+
|
5
|
+
it "raises an ArgumentError when typecast is unknown" do
|
6
|
+
lambda { SMG::Mapping::TypeCasts[:bogus, "42"] }.should raise_error ArgumentError, %r{Can't typecast to :bogus}
|
7
|
+
end
|
8
|
+
|
9
|
+
it "is able to typecast (Stringable) into Fixnum" do
|
10
|
+
SMG::Mapping::TypeCasts[:integer, "42"].should == 42
|
11
|
+
SMG::Mapping::TypeCasts[:integer, nil ].should == 0
|
12
|
+
end
|
13
|
+
|
14
|
+
it "is able to typecast (Stringable) into Symbol" do
|
15
|
+
SMG::Mapping::TypeCasts[:symbol, "something"].should == :something
|
16
|
+
end
|
17
|
+
|
18
|
+
it "is able to typecast (Stringable) into Time" do
|
19
|
+
source = 'Thu Apr 15 18:16:23 +0400 2010'
|
20
|
+
value = SMG::Mapping::TypeCasts[:datetime, source]
|
21
|
+
value.should == Time.parse(source)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "is able to typecast (Stringable) into Date" do
|
25
|
+
source = 'Thu Apr 15 18:16:23 +0400 2010'
|
26
|
+
value = SMG::Mapping::TypeCasts[:date, source]
|
27
|
+
value.should == Date.parse(source)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "is able to typecast (Stringable) into URI" do
|
31
|
+
source = "http://example.org:4567/foo?bar=baz"
|
32
|
+
value = SMG::Mapping::TypeCasts[:uri, source]
|
33
|
+
value.should == URI.parse(source)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is able to typecast (Stringable) into Float" do
|
37
|
+
SMG::Mapping::TypeCasts[ :float , nil ].should == 0.00
|
38
|
+
SMG::Mapping::TypeCasts[ :float , "42." ].should == 42.00
|
39
|
+
SMG::Mapping::TypeCasts[ :float , ".42" ].should == 0.42
|
40
|
+
SMG::Mapping::TypeCasts[ :float , "42" ].should == 42.00
|
41
|
+
end
|
42
|
+
|
43
|
+
it "is able to typecast (Stringable) into Boolean" do
|
44
|
+
SMG::Mapping::TypeCasts[ :boolean , nil ].should == nil
|
45
|
+
SMG::Mapping::TypeCasts[ :boolean , "true" ].should == true
|
46
|
+
SMG::Mapping::TypeCasts[ :boolean , "something" ].should == true
|
47
|
+
SMG::Mapping::TypeCasts[ :boolean , "false" ].should == false
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
# EOF
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe SMG::Resource do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@klass = Class.new { include SMG::Resource }
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "when included" do
|
10
|
+
|
11
|
+
it "extends class with the SMG::Model" do
|
12
|
+
@klass.should be_an SMG::Model
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#parsed!" do
|
18
|
+
|
19
|
+
it "marks resource as parsed" do
|
20
|
+
resource = @klass.new
|
21
|
+
resource.should_not be_parsed
|
22
|
+
resource.parsed!
|
23
|
+
resource.should be_parsed
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
# EOF
|