resto 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/lib/blankslate.rb +110 -0
  2. data/lib/resto.rb +264 -0
  3. data/lib/resto/attributes.rb +56 -0
  4. data/lib/resto/extra/copy.rb +34 -0
  5. data/lib/resto/extra/delegation.rb +26 -0
  6. data/lib/resto/extra/hash_args.rb +56 -0
  7. data/lib/resto/format.rb +20 -0
  8. data/lib/resto/format/default.rb +11 -0
  9. data/lib/resto/format/json.rb +30 -0
  10. data/lib/resto/format/plain.rb +14 -0
  11. data/lib/resto/format/xml.rb +66 -0
  12. data/lib/resto/property.rb +50 -0
  13. data/lib/resto/property/handler.rb +57 -0
  14. data/lib/resto/property/integer.rb +29 -0
  15. data/lib/resto/property/string.rb +19 -0
  16. data/lib/resto/property/time.rb +43 -0
  17. data/lib/resto/request/base.rb +88 -0
  18. data/lib/resto/request/factory.rb +66 -0
  19. data/lib/resto/request/header.rb +58 -0
  20. data/lib/resto/request/option.rb +126 -0
  21. data/lib/resto/request/uri.rb +50 -0
  22. data/lib/resto/response/base.rb +85 -0
  23. data/lib/resto/translator/request_factory.rb +44 -0
  24. data/lib/resto/translator/response_factory.rb +28 -0
  25. data/lib/resto/validate.rb +37 -0
  26. data/lib/resto/validate/inclusion.rb +39 -0
  27. data/lib/resto/validate/length.rb +36 -0
  28. data/lib/resto/validate/presence.rb +24 -0
  29. data/lib/resto/version.rb +5 -0
  30. data/resto.gemspec +43 -0
  31. data/spec/resto/extra/copy_spec.rb +58 -0
  32. data/spec/resto/extra/hash_args_spec.rb +71 -0
  33. data/spec/resto/format/default_spec.rb +24 -0
  34. data/spec/resto/format/json_spec.rb +29 -0
  35. data/spec/resto/format/plain_spec.rb +21 -0
  36. data/spec/resto/format/xml_spec.rb +105 -0
  37. data/spec/resto/property/handler_spec.rb +57 -0
  38. data/spec/resto/property/integer_spec.rb +67 -0
  39. data/spec/resto/property/time_spec.rb +124 -0
  40. data/spec/resto/property_spec.rb +60 -0
  41. data/spec/resto/request/base_spec.rb +253 -0
  42. data/spec/resto/request/factory_spec.rb +114 -0
  43. data/spec/resto/translator/response_factory_spec.rb +93 -0
  44. data/spec/resto/validate/presence_spec.rb +102 -0
  45. data/spec/resto_spec.rb +531 -0
  46. data/spec/spec_helper.rb +119 -0
  47. metadata +48 -3
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ class Article
5
+ def initialize; @errors = {}; end
6
+ def title_without_cast; " 200 "; end
7
+ def empty_title_without_cast; " "; end
8
+ def errors; @errors; end
9
+ def add_error(key, error); @errors.store(key, error); end
10
+ end
11
+
12
+ class AProperty;
13
+ include Resto::Property;
14
+ def cast(value, errors); value.to_i; end
15
+ end
16
+
17
+ describe Resto::Property::Handler do
18
+ let(:article) { Article.new }
19
+ let(:property) { AProperty.new(:title) }
20
+ let(:property2) { AProperty.new(:empty_title) }
21
+
22
+ context "#add(property)" do
23
+ before { subject.add(property) }
24
+
25
+ describe "#attribute_key(property_key)" do
26
+ it { subject.attribute_key('title').should == :title }
27
+ end
28
+
29
+ describe "cast(:property_key, '200', errors)" do
30
+ it { subject.cast(:title, '200', nil).should == 200 }
31
+ end
32
+
33
+ describe "#attribute_key('non_existing_title')" do
34
+ it { subject.attribute_key('non_existing_title').should == false }
35
+ end
36
+
37
+ context "#add(other_property)" do
38
+ describe "#validate(article)" do
39
+ before do
40
+ property.validate_presence
41
+ property2.validate_presence
42
+ subject.add(property2)
43
+ subject.validate(article)
44
+ end
45
+
46
+ context "then article has the following error" do
47
+ it { article.errors.fetch(:title_presence, false).should == nil }
48
+
49
+ it do
50
+ article.errors.fetch(:empty_title_presence, false)
51
+ .should == ":empty_title can’t be blank"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'resto/property'
5
+
6
+ describe Resto::Property::Integer do
7
+
8
+ context "Resto::Property::Integer.new(:age)" do
9
+ let(:errors) { {} }
10
+ subject { Resto::Property::Integer.new(:age) }
11
+
12
+ context ".cast(20, errors)" do
13
+ it("returns 20 with no errors") do
14
+ subject.cast(20, errors).should == 20
15
+ errors.fetch(:age_integer, false).should == nil
16
+ end
17
+ end
18
+
19
+ context ".cast('22', errors)" do
20
+ it("returns 22 with no errors") do
21
+ subject.cast('22', errors).should == 22
22
+ errors.fetch(:age_integer, false).should == nil
23
+ end
24
+ end
25
+
26
+ context ".cast('', errors)" do
27
+ it("returns nil with no errors") do
28
+ subject.cast('', errors).should == nil
29
+ errors.fetch(:age_integer, false).should == nil
30
+ end
31
+ end
32
+ context ".cast(' ', errors)" do
33
+ it("returns nil with no errors") do
34
+ subject.cast(' ', errors).should == nil
35
+ errors.fetch(:age_integer, false).should == nil
36
+ end
37
+ end
38
+
39
+ context ".cast(nil, errors)" do
40
+ it("returns nil with no errors") do
41
+ subject.cast(nil, errors).should == nil
42
+ errors.fetch(:age_integer, false).should == nil
43
+ end
44
+ end
45
+
46
+ context ".cast('22q', errors)" do
47
+ it("returns nil and sets errors[:age_integer]") do
48
+ subject.cast('22q', errors).should == nil
49
+ errors.fetch(:age_integer, false).should == ':age is not an integer.'
50
+ end
51
+ end
52
+
53
+ context ".cast('q22', errors)" do
54
+ it("returns nil and sets errors[:age_integer]") do
55
+ subject.cast('q22', errors).should == nil
56
+ errors.fetch(:age_integer, false).should == ':age is not an integer.'
57
+ end
58
+ end
59
+ context ".cast('twenty', errors)" do
60
+ it("returns nil and sets errors[:age_integer]") do
61
+ subject.cast('twenty', errors).should == nil
62
+ errors.fetch(:age_integer, false).should == ':age is not an integer.'
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'resto/property'
5
+
6
+ describe Resto::Property::Time do
7
+ let(:iso_8601_plus) { "2010-10-25T11:48:00+00:00" } # UTC
8
+ let(:iso_8601_minus) { "2010-10-25T23:48:00-00:00" } # UTC
9
+ let(:iso_8601_z) { "2010-10-26T12:48:00Z" } # UTC
10
+ let(:iso_8601_z_summer) { "2010-05-26T12:48:00Z" } # UTC
11
+ let(:iso_8601_cet_summer) { "2011-05-01T14:46:00+02:00" } #GMT +2, UTC +2
12
+ let(:iso_8601_cet_winter) { "2011-01-01T14:46:00+01:00" } #GMT +1, UTC +1
13
+
14
+ let(:errors) { {} }
15
+ subject { Resto::Property::Time.new(:date_of_birth) }
16
+
17
+ describe ".cast(time_string, errors)" do
18
+ context "local time is 2010-10-25T12:00:00 PST" do
19
+ it "returns a time object parsed from the string" do
20
+ at_time("2010-10-25T12:00:00 PST", '-08:00') do #UTC -8
21
+ time = subject.cast(iso_8601_plus, errors)
22
+ time.iso8601.should == '2010-10-25T03:48:00-08:00'
23
+ time.utc.iso8601.should == '2010-10-25T11:48:00Z'
24
+ errors.fetch(:date_of_birth_time, false).should == nil
25
+ end
26
+ end
27
+
28
+ it "returns a time object parsed from the string" do
29
+ at_time("2010-10-25T12:00:00 PST", '-08:00') do #UTC -8
30
+ time = subject.cast(iso_8601_cet_winter, errors)
31
+ time.iso8601.should == '2011-01-01T05:46:00-08:00'
32
+ time.utc.iso8601.should == '2011-01-01T13:46:00Z'
33
+ errors.fetch(:date_of_birth_time, false).should == nil
34
+ end
35
+ end
36
+
37
+ it "returns a time object parsed from the string" do
38
+ at_time("2010-10-25T12:00:00 PST", '-08:00') do #UTC -8
39
+ time = subject.cast(iso_8601_cet_summer, errors)
40
+ time.iso8601.should == '2011-05-01T04:46:00-08:00'
41
+ time.utc.iso8601.should == '2011-05-01T12:46:00Z'
42
+ errors.fetch(:date_of_birth_time, false).should == nil
43
+ end
44
+ end
45
+
46
+ it "returns a time object parsed from the string" do
47
+ at_time("2010-10-25T12:00:00 PST", '-08:00') do #UTC -8
48
+ time = subject.cast(iso_8601_z_summer, errors)
49
+ time.localtime.iso8601.should == '2010-05-26T04:48:00-08:00'
50
+ time.utc.iso8601.should == '2010-05-26T12:48:00Z'
51
+ errors.fetch(:date_of_birth_time, false).should == nil
52
+ end
53
+ end
54
+ end
55
+
56
+ context ".cast('', errors)" do
57
+ it("returns nil with no errors") do
58
+ subject.cast('', errors).should == nil
59
+ errors.fetch(:date_of_birth_time, false).should == nil
60
+ end
61
+ end
62
+ context ".cast(' ', errors)" do
63
+ it("returns nil with no errors") do
64
+ subject.cast(' ', errors).should == nil
65
+ errors.fetch(:date_of_birth_time, false).should == nil
66
+ end
67
+ end
68
+
69
+ context ".cast(nil, errors)" do
70
+ it("returns nil with no errors") do
71
+ subject.cast(nil, errors).should == nil
72
+ errors.fetch(:date_of_birth_time, false).should == nil
73
+ end
74
+ end
75
+
76
+ context ".cast('q', errors)" do
77
+ it("returns nil and sets errors[:date_of_birth_time]") do
78
+ subject.cast('q', errors).should == nil
79
+ errors.fetch(:date_of_birth_time, false).should ==
80
+ ':date_of_birth is not a valid time format.'
81
+ end
82
+ end
83
+
84
+ context ".cast('22q', errors)" do
85
+ it("returns nil and sets errors[:date_of_birth_time]") do
86
+ subject.cast('22q', errors).should == nil
87
+ errors.fetch(:date_of_birth_time, false).should ==
88
+ ':date_of_birth is not a valid time format.'
89
+ end
90
+ end
91
+
92
+ context ".cast('q22', errors)" do
93
+ it("returns nil and sets errors[:date_of_birth_time]") do
94
+ subject.cast('q22', errors).should == nil
95
+ errors.fetch(:date_of_birth_time, false).should ==
96
+ ':date_of_birth is not a valid time format.'
97
+ end
98
+ end
99
+
100
+ context ".cast('twenty', errors)" do
101
+ it("returns nil and sets errors[:date_of_birth_time]") do
102
+ subject.cast('twenty', errors).should == nil
103
+ errors.fetch(:date_of_birth_time, false).should ==
104
+ ':date_of_birth is not a valid time format.'
105
+ end
106
+ end
107
+
108
+ context ".cast('2010-11-02T:1X', errors)" do
109
+ it("returns nil and sets errors[:date_of_birth_time]") do
110
+ subject.cast('2010-11-02T:1X', errors).should == nil
111
+ errors.fetch(:date_of_birth_time, false).should ==
112
+ ':date_of_birth is not a valid time format.'
113
+ end
114
+ end
115
+
116
+ context ".cast('22/02/2010 00:00:00 UTC', errors)" do
117
+ it("returns a time object parsed from the string") do
118
+ time = subject.cast('22/02/2010 00:00:00 UTC', errors)
119
+ time.utc.iso8601.should == '2010-02-22T00:00:00Z'
120
+ errors.fetch(:date_of_birth_time, false).should == nil
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ class Article
5
+ def initialize; @errors = {}; end
6
+ def title_without_cast; " 200 "; end
7
+ def empty_title_without_cast; " "; end
8
+ def errors; @errors; end
9
+ def add_error(key, error); @errors.store(key, error); end
10
+ end
11
+
12
+ class AProperty; include Resto::Property; end
13
+
14
+ describe Resto::Property do
15
+ let(:article) { Article.new }
16
+
17
+ context "AProperty.new(:title, :remote_name => :a_very_bad__title_name)" do
18
+ subject { AProperty.new(:title, :remote_name => :a_very_bad__title_name) }
19
+
20
+ its(:remote_key) { should == 'a_very_bad__title_name' }
21
+ its(:attribute_key) { should == :title }
22
+ its(:attribute_key_as_string) { should == 'title' }
23
+
24
+ context "when #validate_presence is called" do
25
+ before { subject.validate_presence }
26
+
27
+ describe "#validate(article, :title)" do
28
+ context "then article.errors" do
29
+
30
+ before { subject.validate(article, :title) }
31
+
32
+ it { article.errors[:title_presence].should == nil }
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ context "AProperty.new(:empty_title)" do
39
+ subject { AProperty.new(:empty_title) }
40
+
41
+ its(:remote_key) { should == 'empty_title' }
42
+ its(:attribute_key) { should == :empty_title }
43
+ its(:attribute_key_as_string) { should == 'empty_title' }
44
+
45
+ context "when #validate_presence is called" do
46
+ before { subject.validate_presence }
47
+
48
+ describe "#validate(article, :empty_title)" do
49
+ context "then article.errors" do
50
+ before { subject.validate(article, :empty_title) }
51
+
52
+ it {
53
+ article.errors[:empty_title_presence]
54
+ .should == ":empty_title can’t be blank"
55
+ }
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,253 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+ require 'yajl'
5
+ require 'resto/request/base'
6
+
7
+ describe Resto::Request::Base do
8
+
9
+ context "Resto::Request::Base.new" do
10
+
11
+ its(:composed_headers) do
12
+ should == { "accept"=> "*/*", "user-agent"=> "Ruby" }
13
+ end
14
+
15
+ its(:current_formatter) { should == Resto::Format::Default }
16
+
17
+ its(:read_host) { should == nil }
18
+ its(:read_port) { should == 80 }
19
+ its(:composed_path) { should == '/' }
20
+
21
+ describe "@request" do
22
+ it do
23
+ subject.instance_eval { @request }
24
+ .should be_instance_of(Resto::Request::Factory)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "#content_type('application/x-www-form-urlencoded')" do
30
+
31
+ before { subject.content_type('application/x-www-form-urlencoded') }
32
+
33
+ its(:composed_headers) do
34
+ should == { 'content-type' => 'application/x-www-form-urlencoded',
35
+ "accept"=> "*/*", "user-agent"=> "Ruby" }
36
+ end
37
+ end
38
+
39
+ context "#content_type('text/html').headers({'content-type' => 'text/plain',
40
+ 'User-agent' => 'Ruby' })" do
41
+ before do
42
+ subject.content_type('text/html')
43
+ .headers({'content-type' => 'text/plain', 'user-agent' => 'Ruby' })
44
+ end
45
+
46
+ its(:composed_headers) do
47
+ should == { 'content-type' => 'text/plain',
48
+ "accept"=> "*/*",
49
+ "user-agent"=> "Ruby" }
50
+ end
51
+ end
52
+
53
+ context "#basic_auth('username' => 'developer', 'password' => 'secret')
54
+ .content_type('text/html')" do
55
+
56
+ before do
57
+ subject.basic_auth('username' => "developer", "password" => "secret")
58
+ .content_type('text/html')
59
+ end
60
+
61
+ its(:composed_headers) do
62
+
63
+ should == { 'authorization' => basic_encode('developer', 'secret'),
64
+ 'content-type' => 'text/html',
65
+ "accept"=> "*/*",
66
+ "user-agent"=> "Ruby" }
67
+ end
68
+ end
69
+
70
+ context "#basic_auth('username' => 'developer', 'password' => 'secret')
71
+ .headers('content-type' => 'text/plain')" do
72
+
73
+ before { subject.headers('content-type' => 'text/plain') }
74
+
75
+ its(:composed_headers) do
76
+ should == { 'content-type' => 'text/plain',
77
+ "accept"=> "*/*",
78
+ "user-agent"=> "Ruby" }
79
+ end
80
+ end
81
+
82
+ context "#url('www.aftonbladet.se/')" do
83
+
84
+ before { subject.url('www.aftonbladet.se/') }
85
+
86
+ its(:read_host) { should == 'www.aftonbladet.se' }
87
+ its(:read_port) { should == 80 }
88
+ its(:composed_path) { should == '/' }
89
+ end
90
+
91
+ context "#url('www.aftonbladet.se')" do
92
+
93
+ before { subject.url('www.aftonbladet.se') }
94
+
95
+ its(:read_host) { should == 'www.aftonbladet.se' }
96
+ its(:read_port) { should == 80 }
97
+ its(:composed_path) { should == '/' }
98
+ end
99
+
100
+ context "#url('http://www.aftonbladet.se:92/customers')" do
101
+
102
+ before { subject.url('http://www.aftonbladet.se:92/customers') }
103
+
104
+ its(:read_host) { should == 'www.aftonbladet.se' }
105
+ its(:read_port) { should == 92 }
106
+ its(:composed_path) { should == '/customers' }
107
+ end
108
+
109
+ context "Resto::Request::Base.new()
110
+ .url('http://www.aftonbladet.se:92/customers)
111
+ .query('q=adam')
112
+ .params('longUrl' => 'http://betaworks.com', 'short' => 'htt')" do
113
+
114
+ before do
115
+ subject.url('http://www.aftonbladet.se:92/customers')
116
+ .query('q=adam')
117
+ .params('longUrl' => 'http://betaworks.com', 'short' => 'htt')
118
+ end
119
+
120
+ its(:read_host) { should == 'www.aftonbladet.se' }
121
+ its(:read_port) { should == 92 }
122
+ its(:composed_path) do
123
+ should == '/customers?q=adam&longUrl=http%3A%2F%2Fbetaworks.com&short=htt'
124
+ end
125
+ end
126
+
127
+ context "#port(40)
128
+ .url('http://www.aftonbladet.se:92/customers)
129
+ .query('q=adam')
130
+ .path('contacts')" do
131
+
132
+ before do
133
+ subject.port(40)
134
+ .url('http://www.aftonbladet.se:92/customers')
135
+ .query('q=adam')
136
+ .path('contacts')
137
+ end
138
+
139
+ its(:read_host) { should == 'www.aftonbladet.se' }
140
+ its(:read_port) { should == 40 }
141
+ its(:composed_path) { should == '/contacts?q=adam' }
142
+ end
143
+
144
+ context "#url('http://www.aftonbladet.se:92/customers/?q=adam')" do
145
+
146
+ before { subject.url('http://www.aftonbladet.se:92/customers/?q=adam') }
147
+
148
+ its(:read_host) { should == 'www.aftonbladet.se' }
149
+ its(:read_port) { should == 92 }
150
+ its(:composed_path) { should == '/customers/?q=adam' }
151
+ end
152
+
153
+ context "#url('http://www.aftonbladet.se:92/customers/?q=adam')
154
+ .append_path(1)" do
155
+
156
+ before do
157
+ subject.url('http://www.aftonbladet.se:92/customers/?q=adam')
158
+ .append_path(1)
159
+ end
160
+
161
+ its(:read_host) { should == 'www.aftonbladet.se' }
162
+ its(:read_port) { should == 92 }
163
+ its(:composed_path) { should == '/customers/1?q=adam' }
164
+ end
165
+
166
+ context "#url('http://www.aftonbladet.se:92/customers/?q=adam')
167
+ .query('q=take presendent')" do
168
+
169
+ before do
170
+ subject.url('http://www.aftonbladet.se:92/customers/?q=adam')
171
+ .query("q=take presendent")
172
+ end
173
+
174
+ its(:read_host) { should == 'www.aftonbladet.se' }
175
+ its(:read_port) { should == 92 }
176
+ its(:composed_path) { should == '/customers/?q=take presendent' }
177
+ end
178
+
179
+ context "#host('www.take_presedent.se')
180
+ .url('http://www.aftonbladet.se:92/customers/?q=adam')
181
+ .query('q=take presendent')" do
182
+
183
+ before do
184
+ subject.host('www.take-presedent.se')
185
+ .url('http://www.aftonbladet.se:92/customers/?q=adam')
186
+ .query('q=take presendent')
187
+ end
188
+
189
+ its(:read_host) { should == 'www.take-presedent.se' }
190
+ its(:read_port) { should == 92 }
191
+ its(:composed_path) { should == '/customers/?q=take presendent' }
192
+ end
193
+
194
+ context "Resto::Request::Base.new.body('body text')" do
195
+ before { subject.body('body text') }
196
+
197
+ its(:read_body) { should == 'body text' }
198
+ end
199
+
200
+ describe "#body" do
201
+
202
+ context "when formatter is Resto::Format::Default" do
203
+ before { subject.body('body text') }
204
+
205
+ its(:read_body) { should == 'body text' }
206
+ end
207
+
208
+ context "when formatter is Resto::Format::Json" do
209
+ before do
210
+ subject.format(:json)
211
+ .body( { :foo => 12425125, :bar => "some string" } )
212
+ end
213
+
214
+ its(:read_body) do
215
+ should == Yajl::Encoder.encode({ :foo => 12425125,
216
+ :bar => "some string" })
217
+ end
218
+ end
219
+ end
220
+
221
+ context "Resto::Request::Base.new(RequestKlass)" do
222
+ subject do
223
+ request_object = mock('request',
224
+ :head => "head",
225
+ :get => "get",
226
+ :post => "post",
227
+ :put => "put",
228
+ :delete => "delete")
229
+ Resto::Request::Base.new(mock('request_klass', :new => request_object))
230
+ end
231
+
232
+ it "delegates method :head to Request instance" do
233
+ subject.head.should == "head"
234
+ end
235
+
236
+ it "delegates method :get to Request instance" do
237
+ subject.get.should == "get"
238
+ end
239
+
240
+ it "delegates method :post to Request instance" do
241
+ subject.post.should == "post"
242
+ end
243
+
244
+ it "delegates method :put to Request instance" do
245
+ subject.put.should == "put"
246
+ end
247
+
248
+ it "delegates method :delete to Request instance" do
249
+ subject.delete.should == "delete"
250
+ end
251
+ end
252
+
253
+ end