lazy_resource 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -46,7 +46,6 @@ Or install it yourself as:
46
46
 
47
47
  me = User.find(1) # => GET /users/1
48
48
  bobs = User.where(:first_name => 'Bob') # => GET /users?first_name=Bob
49
- sam = User.find_by_first_name('Sam') # => GET /users?first_name=Sam
50
49
  terry = User.new(:first_name => 'Terry', :last_name => 'Simpson')
51
50
  terry.save # => POST /users
52
51
  terry.last_name = 'Jackson'
@@ -96,6 +95,39 @@ was saved. Pretty neat, eh?
96
95
  Sure thing! Take a look at the files in the `examples` directory, or
97
96
  read through the specs.
98
97
 
98
+ ### How about a section of random features?
99
+
100
+ Here you go:
101
+
102
+ Fetch associations without hitting the URL generation code.
103
+
104
+ class Photo
105
+ include LazyResource::Resource
106
+
107
+ attribute :id, Fixnum
108
+ attribute :photographer_url, String
109
+ attribute :photographer, User, :using => :photographer_url
110
+
111
+ # or define it yourself
112
+ def photographer_url
113
+ "/path/to/photographer"
114
+ end
115
+ end
116
+
117
+ Parsing responses like { 'photo': ... }
118
+
119
+ class Photo
120
+ include LazyResource::Resource
121
+
122
+ self.root_node_name = 'photo'
123
+ end
124
+
125
+ or multiple options
126
+
127
+ class Photo
128
+ self.root_node_name = ['photo', 'photos']
129
+ end
130
+
99
131
  ## Contributing
100
132
 
101
133
  1. Fork it
@@ -129,5 +161,4 @@ Thanks to:
129
161
  ## TODO
130
162
 
131
163
  * Clean up `LazyResource::Attributes#create_setter`
132
- * Add more specs for associations
133
164
 
@@ -4,8 +4,8 @@ require File.expand_path('../lib/lazy_resource/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Andrew Latimer"]
6
6
  gem.email = ["andrew@elpasoera.com"]
7
- gem.description = %q{ActiveResource with it's feet up. The write less, do more consumer of delicious APIs.}
8
- gem.summary = %q{ActiveResource with it's feet up. The write less, do more consumer of delicious APIs.}
7
+ gem.description = %q{ActiveResource with its feet up. The write less, do more consumer of delicious APIs.}
8
+ gem.summary = %q{ActiveResource with its feet up. The write less, do more consumer of delicious APIs.}
9
9
  gem.homepage = "http://github.com/ahlatimer/lazy_resource"
10
10
 
11
11
  gem.files = `git ls-files`.split($\)
@@ -18,5 +18,5 @@ Gem::Specification.new do |gem|
18
18
  gem.add_dependency 'activemodel', '>= 3.1.0'
19
19
  gem.add_dependency 'activesupport', '>= 3.1.0'
20
20
  gem.add_dependency 'json', '>= 1.5.2'
21
- gem.add_dependency 'typhoeus', '0.4.2'
21
+ gem.add_dependency 'typhoeus', '0.6.1'
22
22
  end
@@ -73,8 +73,8 @@ module LazyResource
73
73
 
74
74
  if @#{name}.nil?
75
75
  @#{name} = LazyResource::Relation.new(#{type.first}, :fetched => true)
76
+ request = LazyResource::Request.new(self.#{options[:using]}, @#{name}, :headers => @#{name}.headers)
76
77
  @#{name}.fetched = false
77
- request = LazyResource::Request.new(self.#{options[:using]}, @#{name})
78
78
  self.class.request_queue.queue(request)
79
79
  end
80
80
 
@@ -1,7 +1,7 @@
1
1
  module Typhoeus
2
2
  class Hydra
3
3
  def run_with_logging
4
- log = LazyResource.debug && LazyResource.logger && @multi.active > 0 && @multi.running <= 0
4
+ log = LazyResource.debug && LazyResource.logger && @multi.items_queued_but_not_running?
5
5
  if log
6
6
  LazyResource.logger.info "Processing requests:"
7
7
  start_time = Time.now
@@ -17,8 +17,12 @@ module Typhoeus
17
17
  alias_method :run_without_logging, :run
18
18
  alias_method :run, :run_with_logging
19
19
  end
20
+ end
20
21
 
22
+ module Ethon
21
23
  class Multi
22
- attr_reader :active, :running
24
+ def items_queued_but_not_running?
25
+ easy_handles.size > 0 && running_count <= 0
26
+ end
23
27
  end
24
28
  end
@@ -4,14 +4,10 @@ module LazyResource
4
4
  [:post, :put, :get, :delete].each do |method|
5
5
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
6
6
  def #{method}(path, body='', status=200, response_headers={})
7
- request_queue.stub(:#{method}, path).and_return(Typhoeus::Response.new(:code => status, :headers => response_headers, :body => body, :time => 0.3))
7
+ Typhoeus.stub(path, :method => :#{method}).and_return(Typhoeus::Response.new(:code => status, :headers => response_headers, :body => body, :time => 0.3))
8
8
  end
9
9
  RUBY
10
10
  end
11
-
12
- def request_queue
13
- Thread.current[:request_queue] ||= Typhoeus::Hydra.new
14
- end
15
11
  end
16
12
 
17
13
  class << self
@@ -44,7 +44,7 @@ module LazyResource
44
44
  end
45
45
 
46
46
  def mapped_root_node_name(objects)
47
- if self.root_node_name
47
+ if self.root_node_name && objects.respond_to?(:keys)
48
48
  root_node_names = self.root_node_name.is_a?(Array) ? self.root_node_name : [self.root_node_name]
49
49
  mapped_name = (root_node_names.map(&:to_s) & objects.keys).first
50
50
  end
@@ -53,6 +53,7 @@ module LazyResource
53
53
 
54
54
  def load(hash, persisted=true)
55
55
  hash.fetched = true and return hash if hash.kind_of?(LazyResource::Mapping)
56
+ return if hash.nil?
56
57
 
57
58
  self.tap do |resource|
58
59
  resource.persisted = persisted
@@ -42,10 +42,10 @@ module LazyResource
42
42
  def load(objects)
43
43
  @fetched = true
44
44
 
45
- if @klass.root_node_name && objects.respond_to?(:key?) && objects.key?(@klass.root_node_name.to_s)
46
- other_objects = objects.dup
47
- objects = other_objects.delete(@klass.root_node_name.to_s)
48
- @other_attributes = other_objects
45
+ if mapped_name = @klass.mapped_root_node_name(objects)
46
+ other_attributes = objects.dup
47
+ objects = other_attributes.delete(mapped_name)
48
+ @other_attributes = other_attributes
49
49
  end
50
50
 
51
51
  @result = objects.map do |object|
@@ -14,18 +14,14 @@ module LazyResource
14
14
  super(url, options)
15
15
 
16
16
  @resource = resource
17
- self.on_complete = on_complete_proc
18
-
19
- self
20
- end
21
-
22
- def on_complete_proc
23
- Proc.new do |response|
17
+ self.on_complete do
24
18
  log_response(response) if LazyResource.debug && LazyResource.logger
25
19
  @response = response
26
20
  handle_errors unless SUCCESS_STATUSES.include?(@response.code)
27
21
  parse
28
22
  end
23
+
24
+ self
29
25
  end
30
26
 
31
27
  def log_response(response)
@@ -1,3 +1,3 @@
1
1
  module LazyResource
2
- VERSION = "0.3.3"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -91,9 +91,9 @@ describe LazyResource::Attributes do
91
91
  end
92
92
 
93
93
  it 'finds a collection using the specified url' do
94
- relation = LazyResource::Relation.new(Post)
94
+ relation = LazyResource::Relation.new(Post, :headers => {})
95
95
  request = LazyResource::Request.new(@foo.posts_url, relation)
96
- LazyResource::Request.should_receive(:new).with(@foo.posts_url, relation).and_return(request)
96
+ LazyResource::Request.should_receive(:new).with(@foo.posts_url, relation, :headers => relation.headers).and_return(request)
97
97
  LazyResource::Relation.should_receive(:new).with(Post, :fetched => true).and_return(relation)
98
98
  @foo.class.request_queue.should_receive(:queue).with(request)
99
99
  @foo.fetched = false
@@ -17,22 +17,22 @@ describe Typhoeus::Hydra do
17
17
  end
18
18
 
19
19
  it 'logs if logging is enabled, there are items to process, and the queue has not yet started processing' do
20
- @multi.send(:instance_variable_set, "@active", 10)
21
- @multi.send(:instance_variable_set, "@running", 0)
20
+ @multi.stub!(:easy_handles).and_return([1,2,3])
21
+ @multi.stub!(:running_count).and_return(0)
22
22
  LazyResource.logger.should_receive(:info).twice
23
23
  @hydra.run_with_logging
24
24
  end
25
25
 
26
26
  it 'does not log if there are no items to process' do
27
- @multi.send(:instance_variable_set, "@active", 0)
28
- @multi.send(:instance_variable_set, "@running", 0)
27
+ @multi.stub!(:easy_handles).and_return([])
28
+ @multi.stub!(:running_count).and_return(0)
29
29
  LazyResource.logger.should_not_receive(:info)
30
30
  @hydra.run_with_logging
31
31
  end
32
32
 
33
33
  it 'does not log if the queue is already being processed' do
34
- @multi.send(:instance_variable_set, "@active", 10)
35
- @multi.send(:instance_variable_set, "@running", 5)
34
+ @multi.stub!(:easy_handles).and_return([1,2,3])
35
+ @multi.stub!(:running_count).and_return(3)
36
36
  LazyResource.logger.should_not_receive(:info)
37
37
  @hydra.run_with_logging
38
38
  end
@@ -24,7 +24,8 @@ describe LazyResource do
24
24
  it 'logs when a request completes' do
25
25
  LazyResource.logger.should_receive(:info)
26
26
  request = LazyResource::Request.new('http://example.com', User.new)
27
- request.on_complete_proc.call(Typhoeus::Response.new)
27
+ request.response = Typhoeus::Response.new
28
+ request.execute_callbacks
28
29
  end
29
30
  end
30
31
  end
@@ -75,6 +75,18 @@ describe LazyResource::Mapping do
75
75
  user.comments.to_a.should == @comments
76
76
  end
77
77
 
78
+ it 'should not attempt to load nil associations' do
79
+ user = Foo.load({
80
+ :id => 123,
81
+ :name => 'Andrew',
82
+ :post => nil
83
+ })
84
+
85
+ user.id.should == 123
86
+ user.name.should == 'Andrew'
87
+ user.post.should == nil
88
+ end
89
+
78
90
  it 'loads an array of objects' do
79
91
  users = Foo.load([
80
92
  {
@@ -163,17 +175,44 @@ describe LazyResource::Mapping do
163
175
  user.other_attributes.should == { 'length' => 12 }
164
176
  end
165
177
 
166
- it 'supports multiple root node names with a single resource' do
167
- Foo.root_node_name = [:data, :datum]
168
- user = Foo.new
169
- user.load('data' => { :id => 123 })
170
- user.id.should == 123
171
- end
178
+ describe 'multiple root node names' do
179
+ it 'supports multiple root node names with an instantiated object' do
180
+ Foo.root_node_name = [:data, :datum]
181
+ user = Foo.new
182
+ user.load('data' => { :id => 123 })
183
+ user.id.should == 123
184
+ end
185
+
186
+ it 'suppors multiple root node names with a single resource' do
187
+ Foo.root_node_name = [:data, :datum]
188
+ user = Foo.load('data' => { :id => 123 })
189
+ user.id.should == 123
190
+ end
191
+
192
+ it 'supports multiple root node names with a collection' do
193
+ Foo.root_node_name = [:data, :datum]
194
+ users = Foo.load('data' => [{ :id => 123 }, { :id => 124 }])
195
+ users.map(&:id).should == [123, 124]
196
+ end
172
197
 
173
- it 'supports multiple root node names with a collection' do
174
- Foo.root_node_name = [:data, :datum]
175
- users = Foo.load('data' => [{ :id => 123 }, { :id => 124 }])
176
- users.map(&:id).should == [123, 124]
198
+ it 'sets any other attributes in the hash to #other_attributes for an instantiated object' do
199
+ Foo.root_node_name = [:data, :datum]
200
+ user = Foo.new
201
+ user.load('data' => { :id => 123 }, 'length' => 12)
202
+ user.other_attributes.should == { 'length' => 12 }
203
+ end
204
+
205
+ it 'sets any other attributes in the hash to #other_attributes for a single resource' do
206
+ Foo.root_node_name = [:data, :datum]
207
+ user = Foo.load('data' => { :id => 123 }, 'length' => 12)
208
+ user.other_attributes.should == { 'length' => 12 }
209
+ end
210
+
211
+ it 'sets any other attributes in the hash to #other_attributes for a collection' do
212
+ Foo.root_node_name = [:data, :datum]
213
+ users = Foo.load('data' => [{ :id => 123 }, { :id => 124 }], 'length' => 12)
214
+ users.other_attributes.should == { 'length' => 12 }
215
+ end
177
216
  end
178
217
  end
179
218
 
@@ -22,40 +22,18 @@ describe LazyResource::Request do
22
22
 
23
23
  it 'sets a default Accept header of application/json' do
24
24
  request = LazyResource::Request.new('http://example.com/api', nil)
25
- headers = request.send(:instance_variable_get, "@headers")
26
- headers[:Accept].should == 'application/json'
25
+ request.options[:headers][:Accept].should == 'application/json'
27
26
  end
28
27
 
29
28
  it 'sets the default method of GET' do
30
29
  request = LazyResource::Request.new('http://example.com/api', nil)
31
- request.send(:instance_variable_get, "@method").should == :get
30
+ request.options[:method].should == :get
32
31
  end
33
32
 
34
33
  it 'merges the headers from the current thread' do
35
34
  Thread.current[:default_headers] = { :"X-Access-Token" => 'abc' }
36
35
  request = LazyResource::Request.new('http://example.com/api', nil)
37
- headers = request.send(:instance_variable_get, "@headers")
38
- headers[:"X-Access-Token"].should == 'abc'
39
- end
40
- end
41
-
42
- describe '#on_complete_proc' do
43
- it 'raises an error unless 200 or 201' do
44
- request = LazyResource::Request.new('http://example.com', nil)
45
- response = Typhoeus::Response.new(:code => 404, :headers => {}, :body => '', :time => 0.3)
46
- lambda { request.on_complete_proc.call(response) }.should raise_error(LazyResource::ConnectionError)
47
- end
48
-
49
- it 'does not raise an error on 200' do
50
- request = LazyResource::Request.new('http://example.com', SampleResource.new)
51
- response = Typhoeus::Response.new(:code => 200)
52
- lambda { request.on_complete_proc.call(response) }.should_not raise_error(StandardError)
53
- end
54
-
55
- it 'does not raise an error on 201' do
56
- request = LazyResource::Request.new('http://example.com', SampleResource.new)
57
- response = Typhoeus::Response.new(:code => 201)
58
- lambda { request.on_complete_proc.call(response) }.should_not raise_error(StandardError)
36
+ request.options[:headers][:"X-Access-Token"].should == 'abc'
59
37
  end
60
38
  end
61
39
 
@@ -3,10 +3,6 @@ require 'spec_helper'
3
3
  class Admin < User; end
4
4
 
5
5
  describe LazyResource::Resource do
6
- before :each do
7
- Thread.current[:request_queue].clear_stubs unless Thread.current[:request_queue].nil?
8
- end
9
-
10
6
  describe '#new' do
11
7
  it 'creates an object with the specified attributes' do
12
8
  user = User.new({ :name => 'Andrew', :id => 123 })
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lazy_resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-10 00:00:00.000000000 Z
12
+ date: 2013-02-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - '='
68
68
  - !ruby/object:Gem::Version
69
- version: 0.4.2
69
+ version: 0.6.1
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,8 +74,8 @@ dependencies:
74
74
  requirements:
75
75
  - - '='
76
76
  - !ruby/object:Gem::Version
77
- version: 0.4.2
78
- description: ActiveResource with it's feet up. The write less, do more consumer of
77
+ version: 0.6.1
78
+ description: ActiveResource with its feet up. The write less, do more consumer of
79
79
  delicious APIs.
80
80
  email:
81
81
  - andrew@elpasoera.com
@@ -137,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
137
  version: '0'
138
138
  segments:
139
139
  - 0
140
- hash: -809900452515726390
140
+ hash: -3444122050560505401
141
141
  required_rubygems_version: !ruby/object:Gem::Requirement
142
142
  none: false
143
143
  requirements:
@@ -146,13 +146,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
146
  version: '0'
147
147
  segments:
148
148
  - 0
149
- hash: -809900452515726390
149
+ hash: -3444122050560505401
150
150
  requirements: []
151
151
  rubyforge_project:
152
152
  rubygems_version: 1.8.24
153
153
  signing_key:
154
154
  specification_version: 3
155
- summary: ActiveResource with it's feet up. The write less, do more consumer of delicious
155
+ summary: ActiveResource with its feet up. The write less, do more consumer of delicious
156
156
  APIs.
157
157
  test_files:
158
158
  - spec/fixtures/comment.rb