her 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -179,22 +179,19 @@ gem "faraday_middleware"
179
179
  In your Ruby code:
180
180
 
181
181
  ```ruby
182
- class MyCache
183
- def initialize
184
- @cache = {}
185
- end
186
-
187
- def write(key, value)
188
- @cache[key] = value
182
+ class MyCache < Hash
183
+ def read(key)
184
+ if cached = self[key]
185
+ Marshal.load(cached)
186
+ end
189
187
  end
190
188
 
191
- def read(key)
192
- @cache[key]
189
+ def write(key, data)
190
+ self[key] = Marshal.dump(data)
193
191
  end
194
192
 
195
- def fetch(key, &block)
196
- return value = read(key) if value.nil?
197
- write key, yield
193
+ def fetch(key)
194
+ read(key) || yield.tap { |data| write(key, data) }
198
195
  end
199
196
  end
200
197
 
@@ -445,9 +442,22 @@ Category.all
445
442
  * Better error handling
446
443
  * Better API documentation (using YARD)
447
444
 
448
- ## Contributors
445
+ ## Contribute
449
446
 
450
- Feel free to contribute and submit issues/pull requests [on GitHub](https://github.com/remiprev/her/issues) like these fine folks did:
447
+ Yes please! Feel free to contribute and submit issues/pull requests [on GitHub](https://github.com/remiprev/her/issues).
448
+
449
+ ### How to contribute
450
+
451
+ * Fork the repository
452
+ * Implement your feature or fix
453
+ * Add examples that describe it (in the `spec` directory)
454
+ * Make sure `bundle exec rake spec` passes after your modifications
455
+ * Commit (bonus points for doing it in a `feature-*` branch)
456
+ * Send a pull request!
457
+
458
+ ### Contributors
459
+
460
+ These fine folks helped with Her:
451
461
 
452
462
  * [@jfcixmedia](https://github.com/jfcixmedia)
453
463
  * [@EtienneLem](https://github.com/EtienneLem)
@@ -455,8 +465,6 @@ Feel free to contribute and submit issues/pull requests [on GitHub](https://gith
455
465
  * [@tysontate](https://github.com/tysontate)
456
466
  * [@nfo](https://github.com/nfo)
457
467
 
458
- Take a look at the `spec` folder before you do, and make sure `bundle exec rake spec` passes after your modifications :)
459
-
460
468
  ## License
461
469
 
462
470
  Her is © 2012 [Rémi Prévost](http://exomel.com) and may be freely distributed under the [MIT license](https://github.com/remiprev/her/blob/master/LICENSE). See the `LICENSE` file.
data/UPGRADE.md CHANGED
@@ -4,27 +4,27 @@ Here is a list of backward-incompatible changes that were introduced while Her i
4
4
 
5
5
  * Her no longer includes default middleware when making HTTP requests. The user has now to define all the needed middleware. Before:
6
6
 
7
- Her::API.setup :base_uri => "https://api.example.com" do |builder|
8
- builder.insert(0, FaradayMiddle::OAuth)
9
- end
7
+ Her::API.setup :base_uri => "https://api.example.com" do |builder|
8
+ builder.insert(0, FaradayMiddle::OAuth)
9
+ end
10
10
 
11
11
  Now:
12
12
 
13
- Her::API.setup :base_uri => "https://api.example.com" do |builder|
14
- builder.use FaradayMiddle::OAuth
15
- builder.use Her::Middleware::FirstLevelParseJSON
16
- builder.use Faraday::Request::UrlEncoded
17
- builder.use Faraday::Adapter::NetHttp
18
- end
13
+ Her::API.setup :base_uri => "https://api.example.com" do |builder|
14
+ builder.use FaradayMiddle::OAuth
15
+ builder.use Her::Middleware::FirstLevelParseJSON
16
+ builder.use Faraday::Request::UrlEncoded
17
+ builder.use Faraday::Adapter::NetHttp
18
+ end
19
19
 
20
20
  ## 0.2
21
21
 
22
22
  * The default parser middleware has been replaced to treat first-level JSON data as the resource or collection data. Before it expected this:
23
23
 
24
- { "data": { "id": 1, "name": "Foo" }, "errors": [] }
24
+ { "data": { "id": 1, "name": "Foo" }, "errors": [] }
25
25
 
26
26
  Now it expects this (the `errors` key is not treated as resource data):
27
27
 
28
- { "id": 1, "name": "Foo", "errors": [] }
28
+ { "id": 1, "name": "Foo", "errors": [] }
29
29
 
30
30
  If you still want to get the old behavior, you can use `Her::Middleware::SecondLevelParseJSON` instead of `Her::Middleware::FirstLevelParseJSON` in your middleware stack.
@@ -12,22 +12,19 @@ class TwitterSearchParser < Faraday::Response::Middleware
12
12
  end
13
13
  end
14
14
 
15
- class MyCache
16
- def initialize
17
- @cache = {}
18
- end
19
-
20
- def write(key, value)
21
- @cache[key] = value
15
+ class MyCache < Hash
16
+ def read(key)
17
+ if cached = self[key]
18
+ Marshal.load(cached)
19
+ end
22
20
  end
23
21
 
24
- def read(key)
25
- @cache[key]
22
+ def write(key, data)
23
+ self[key] = Marshal.dump(data)
26
24
  end
27
25
 
28
- def fetch(key, &block)
29
- return value = read(key) if value.nil?
30
- write key, yield
26
+ def fetch(key)
27
+ read(key) || yield.tap { |data| write(key, data) }
31
28
  end
32
29
  end
33
30
 
@@ -35,8 +32,10 @@ $cache = MyCache.new
35
32
 
36
33
  # Initialize API
37
34
  Her::API.setup :base_uri => "http://search.twitter.com" do |builder|
38
- builder.swap Her::Middleware::FirstLevelParseJSON, TwitterSearchParser
35
+ builder.use Faraday::Request::UrlEncoded
39
36
  builder.use FaradayMiddleware::Caching, $cache
37
+ builder.use TwitterSearchParser
38
+ builder.use Faraday::Adapter::NetHttp
40
39
  end
41
40
 
42
41
  # Define classes
@@ -49,6 +48,6 @@ class Tweet
49
48
  end
50
49
 
51
50
  get "/" do
52
- @tweets = Tweet.search("github", :rpp => 30)
51
+ @tweets = Tweet.search("justin bieber", :rpp => 30)
53
52
  haml :index
54
53
  end
@@ -26,7 +26,7 @@ module Her
26
26
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
27
27
  get_raw(path, attrs) do |parsed_data|
28
28
  if parsed_data[:data].is_a?(Array)
29
- new_collection(parsed_data)
29
+ new_collection(parsed_data[:data])
30
30
  else
31
31
  new(parsed_data[:data])
32
32
  end
@@ -43,7 +43,7 @@ module Her
43
43
  def get_collection(path, attrs={}) # {{{
44
44
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
45
45
  get_raw(path, attrs) do |parsed_data|
46
- new_collection(parsed_data)
46
+ new_collection(parsed_data[:data])
47
47
  end
48
48
  end # }}}
49
49
 
@@ -60,7 +60,7 @@ module Her
60
60
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
61
61
  post_raw(path, attrs) do |parsed_data|
62
62
  if parsed_data[:data].is_a?(Array)
63
- new_collection(parsed_data)
63
+ new_collection(parsed_data[:data])
64
64
  else
65
65
  new(parsed_data[:data])
66
66
  end
@@ -77,7 +77,7 @@ module Her
77
77
  def post_collection(path, attrs={}) # {{{
78
78
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
79
79
  post_raw(path, attrs) do |parsed_data|
80
- new_collection(parsed_data)
80
+ new_collection(parsed_data[:data])
81
81
  end
82
82
  end # }}}
83
83
 
@@ -94,7 +94,7 @@ module Her
94
94
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
95
95
  put_raw(path, attrs) do |parsed_data|
96
96
  if parsed_data[:data].is_a?(Array)
97
- new_collection(parsed_data)
97
+ new_collection(parsed_data[:data])
98
98
  else
99
99
  new(parsed_data[:data])
100
100
  end
@@ -111,7 +111,7 @@ module Her
111
111
  def put_collection(path, attrs={}) # {{{
112
112
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
113
113
  put_raw(path, attrs) do |parsed_data|
114
- new_collection(parsed_data)
114
+ new_collection(parsed_data[:data])
115
115
  end
116
116
  end # }}}
117
117
 
@@ -128,7 +128,7 @@ module Her
128
128
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
129
129
  patch_raw(path, attrs) do |parsed_data|
130
130
  if parsed_data[:data].is_a?(Array)
131
- new_collection(parsed_data)
131
+ new_collection(parsed_data[:data])
132
132
  else
133
133
  new(parsed_data[:data])
134
134
  end
@@ -145,7 +145,7 @@ module Her
145
145
  def patch_collection(path, attrs={}) # {{{
146
146
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
147
147
  patch_raw(path, attrs) do |parsed_data|
148
- new_collection(parsed_data)
148
+ new_collection(parsed_data[:data])
149
149
  end
150
150
  end # }}}
151
151
 
@@ -162,7 +162,7 @@ module Her
162
162
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
163
163
  delete_raw(path, attrs) do |parsed_data|
164
164
  if parsed_data[:data].is_a?(Array)
165
- new_collection(parsed_data)
165
+ new_collection(parsed_data[:data])
166
166
  else
167
167
  new(parsed_data[:data])
168
168
  end
@@ -179,7 +179,7 @@ module Her
179
179
  def delete_collection(path, attrs={}) # {{{
180
180
  path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
181
181
  delete_raw(path, attrs) do |parsed_data|
182
- new_collection(parsed_data)
182
+ new_collection(parsed_data[:data])
183
183
  end
184
184
  end # }}}
185
185
 
@@ -39,9 +39,8 @@ module Her
39
39
 
40
40
  # Initialize a collection of resources with raw data from an HTTP request
41
41
  #
42
- # @param [Hash] parsed_data The raw `parsed_data` parsed from the HTTP response
43
- def new_collection(parsed_data) # {{{
44
- collection_data = parsed_data[:data]
42
+ # @param [Array] collection_data An array of model hashes
43
+ def new_collection(collection_data) # {{{
45
44
  Her::Model::ORM.initialize_collection(self.to_s.underscore, collection_data)
46
45
  end # }}}
47
46
 
@@ -68,7 +67,7 @@ module Her
68
67
  # # Fetched via GET "/users"
69
68
  def all(params={}) # {{{
70
69
  request(params.merge(:_method => :get, :_path => "#{build_request_path(params)}")) do |parsed_data|
71
- new_collection(parsed_data)
70
+ new_collection(parsed_data[:data])
72
71
  end
73
72
  end # }}}
74
73
 
@@ -16,11 +16,11 @@ module Her
16
16
  relationships.each do |relationship|
17
17
  if data.include?(relationship[:name])
18
18
  if type == :has_many
19
- data[relationship[:name]] = Her::Model::ORM.initialize_collection(relationship[:name], data[relationship[:name]])
19
+ data[relationship[:name]] = Her::Model::ORM.initialize_collection(relationship[:class_name], data[relationship[:name]])
20
20
  elsif type == :has_one
21
- data[relationship[:name]] = Object.const_get(relationship[:name].to_s.classify).new(data[relationship[:name]])
21
+ data[relationship[:name]] = Object.const_get(relationship[:class_name]).new(data[relationship[:name]])
22
22
  elsif type == :belongs_to
23
- data[relationship[:name]] = Object.const_get(relationship[:name].to_s.classify).new(data[relationship[:name]])
23
+ data[relationship[:name]] = Object.const_get(relationship[:class_name]).new(data[relationship[:name]])
24
24
  end
25
25
  end
26
26
  end
@@ -48,11 +48,12 @@ module Her
48
48
  # # Fetched via GET "/users/1/articles"
49
49
  def has_many(name, attrs={}) # {{{
50
50
  @her_relationships ||= {}
51
- (@her_relationships[:has_many] ||= []) << attrs.merge(:name => name)
51
+ attrs = { :class_name => name.to_s.classify, :name => name }.merge(attrs)
52
+ (@her_relationships[:has_many] ||= []) << attrs
52
53
 
53
54
  define_method(name) do
54
55
  return @data[name] if @data.include?(name) # Do not fetch from API again if we have it in @data
55
- self.class.get_collection("#{self.class.build_request_path(:id => id)}/#{name.to_s.pluralize}")
56
+ Object.const_get(attrs[:class_name]).get_collection("#{self.class.build_request_path(:id => id)}/#{name.to_s.pluralize}")
56
57
  end
57
58
  end # }}}
58
59
 
@@ -76,11 +77,12 @@ module Her
76
77
  # # Fetched via GET "/users/1/organization"
77
78
  def has_one(name, attrs={}) # {{{
78
79
  @her_relationships ||= {}
79
- (@her_relationships[:has_one] ||= []) << attrs.merge(:name => name)
80
+ attrs = { :class_name => name.to_s.classify, :name => name, :foreign_key => "#{name}_id" }.merge(attrs)
81
+ (@her_relationships[:has_one] ||= []) << attrs
80
82
 
81
83
  define_method(name) do
82
84
  return @data[name] if @data.include?(name) # Do not fetch from API again if we have it in @data
83
- self.class.get_resource("#{self.class.build_request_path(:id => id)}/#{name.to_s.singularize}")
85
+ Object.const_get(attrs[:class_name]).get_resource("#{self.class.build_request_path(:id => id)}/#{name.to_s.singularize}")
84
86
  end
85
87
  end # }}}
86
88
 
@@ -104,11 +106,12 @@ module Her
104
106
  # # Fetched via GET "/teams/2"
105
107
  def belongs_to(name, attrs={}) # {{{
106
108
  @her_relationships ||= {}
107
- (@her_relationships[:belongs_to] ||= []) << attrs.merge(:name => name)
109
+ attrs = { :class_name => name.to_s.classify, :name => name, :foreign_key => "#{name}_id" }.merge(attrs)
110
+ (@her_relationships[:belongs_to] ||= []) << attrs
108
111
 
109
112
  define_method(name) do
110
113
  return @data[name] if @data.include?(name) # Do not fetch from API again if we have it in @data
111
- self.class.get_resource("#{Object.const_get(name.to_s.classify).build_request_path(:id => @data["#{name}_id".to_sym])}")
114
+ Object.const_get(attrs[:class_name]).get_resource("#{Object.const_get(name.to_s.classify).build_request_path(:id => @data["#{name}_id".to_sym])}")
112
115
  end
113
116
  end # }}}
114
117
  end
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  end
@@ -2,46 +2,67 @@
2
2
  require File.join(File.dirname(__FILE__), "../spec_helper.rb")
3
3
 
4
4
  describe Her::Model::Relationships do
5
- context "setting relationships" do
5
+ context "setting relationships without details" do
6
6
  before do # {{{
7
7
  spawn_model :User
8
8
  end # }}}
9
9
 
10
10
  it "handles a single 'has_many' relationship" do # {{{
11
11
  User.has_many :comments
12
- User.relationships[:has_many].should == [{ :name => :comments }]
12
+ User.relationships[:has_many].should == [{ :name => :comments, :class_name => "Comment" }]
13
13
  end # }}}
14
14
 
15
15
  it "handles multiples 'has_many' relationship" do # {{{
16
16
  User.has_many :comments
17
17
  User.has_many :posts
18
- User.relationships[:has_many].should == [{ :name => :comments }, { :name => :posts }]
18
+ User.relationships[:has_many].should == [{ :name => :comments, :class_name => "Comment" }, { :name => :posts, :class_name => "Post" }]
19
19
  end # }}}
20
20
 
21
21
  it "handles a single 'has_one' relationship" do # {{{
22
22
  User.has_one :category
23
- User.relationships[:has_one].should == [{ :name => :category }]
23
+ User.relationships[:has_one].should == [{ :name => :category, :class_name => "Category", :foreign_key => "category_id" }]
24
24
  end # }}}
25
25
 
26
26
  it "handles multiples 'has_one' relationship" do # {{{
27
27
  User.has_one :category
28
28
  User.has_one :role
29
- User.relationships[:has_one].should == [{ :name => :category }, { :name => :role }]
29
+ User.relationships[:has_one].should == [{ :name => :category, :class_name => "Category", :foreign_key => "category_id" }, { :name => :role, :class_name => "Role", :foreign_key => "role_id" }]
30
30
  end # }}}
31
31
 
32
32
  it "handles a single belongs_to relationship" do # {{{
33
33
  User.belongs_to :organization
34
- User.relationships[:belongs_to].should == [{ :name => :organization }]
34
+ User.relationships[:belongs_to].should == [{ :name => :organization, :class_name => "Organization", :foreign_key => "organization_id" }]
35
35
  end # }}}
36
36
 
37
37
  it "handles multiples 'belongs_to' relationship" do # {{{
38
38
  User.belongs_to :organization
39
39
  User.belongs_to :family
40
- User.relationships[:belongs_to].should == [{ :name => :organization }, { :name => :family }]
40
+ User.relationships[:belongs_to].should == [{ :name => :organization, :class_name => "Organization", :foreign_key => "organization_id" }, { :name => :family, :class_name => "Family", :foreign_key => "family_id" }]
41
41
  end # }}}
42
42
  end
43
43
 
44
- context "handling relationships" do
44
+ context "setting relationships with details" do
45
+ before do # {{{
46
+ spawn_model :User
47
+ end # }}}
48
+
49
+ it "handles a single 'has_many' relationship" do # {{{
50
+ User.has_many :comments, :class_name => "Post"
51
+ User.relationships[:has_many].should == [{ :name => :comments, :class_name => "Post" }]
52
+ end # }}}
53
+
54
+ it "handles a single 'has_one' relationship" do # {{{
55
+ User.has_one :category, :class_name => "Topic", :foreign_key => "topic_id"
56
+ User.relationships[:has_one].should == [{ :name => :category, :class_name => "Topic", :foreign_key => "topic_id" }]
57
+ end # }}}
58
+
59
+ it "handles a single belongs_to relationship" do # {{{
60
+ User.belongs_to :organization, :class_name => "Business", :foreign_key => "business_id"
61
+ User.relationships[:belongs_to].should == [{ :name => :organization, :class_name => "Business", :foreign_key => "business_id" }]
62
+ end # }}}
63
+ end
64
+
65
+ context "handling relationships without details" do
45
66
  before do # {{{
46
67
  Her::API.setup :base_uri => "https://api.example.com" do |builder|
47
68
  builder.use Her::Middleware::FirstLevelParseJSON
@@ -65,39 +86,44 @@ describe Her::Model::Relationships do
65
86
  spawn_model :Comment
66
87
  spawn_model :Role
67
88
 
68
-
69
89
  @user_with_included_data = User.find(1)
70
90
  @user_without_included_data = User.find(2)
71
91
  end # }}}
72
92
 
73
93
  it "maps an array of included data through has_many" do # {{{
94
+ @user_with_included_data.comments.first.class.should == Comment
74
95
  @user_with_included_data.comments.length.should == 2
75
96
  @user_with_included_data.comments.first.id.should == 2
76
97
  @user_with_included_data.comments.first.body.should == "Tobias, you blow hard!"
77
98
  end # }}}
78
99
 
79
100
  it "fetches data that was not included through has_many" do # {{{
101
+ @user_without_included_data.comments.first.class.should == Comment
80
102
  @user_without_included_data.comments.length.should == 2
81
103
  @user_without_included_data.comments.first.id.should == 4
82
104
  @user_without_included_data.comments.first.body.should == "They're having a FIRESALE?"
83
105
  end # }}}
84
106
 
85
107
  it "maps an array of included data through has_one" do # {{{
108
+ @user_with_included_data.role.class.should == Role
86
109
  @user_with_included_data.role.id.should == 1
87
110
  @user_with_included_data.role.body.should == "Admin"
88
111
  end # }}}
89
112
 
90
113
  it "fetches data that was not included through has_one" do # {{{
114
+ @user_without_included_data.role.class.should == Role
91
115
  @user_without_included_data.role.id.should == 2
92
116
  @user_without_included_data.role.body.should == "User"
93
117
  end # }}}
94
118
 
95
119
  it "maps an array of included data through belongs_to" do # {{{
120
+ @user_with_included_data.organization.class.should == Organization
96
121
  @user_with_included_data.organization.id.should == 1
97
122
  @user_with_included_data.organization.name.should == "Bluth Company"
98
123
  end # }}}
99
124
 
100
125
  it "fetches data that was not included through belongs_to" do # {{{
126
+ @user_without_included_data.organization.class.should == Organization
101
127
  @user_without_included_data.organization.id.should == 1
102
128
  @user_without_included_data.organization.name.should == "Bluth Company"
103
129
  end # }}}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: her
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
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-05-03 00:00:00.000000000Z
12
+ date: 2012-05-05 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -282,7 +282,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
282
282
  version: '0'
283
283
  segments:
284
284
  - 0
285
- hash: -3092731316656290620
285
+ hash: 112971381959523864
286
286
  required_rubygems_version: !ruby/object:Gem::Requirement
287
287
  none: false
288
288
  requirements:
@@ -291,7 +291,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
291
291
  version: '0'
292
292
  segments:
293
293
  - 0
294
- hash: -3092731316656290620
294
+ hash: 112971381959523864
295
295
  requirements: []
296
296
  rubyforge_project:
297
297
  rubygems_version: 1.8.18