her 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MmZjNzAyYWJjNWQyZmJmZDQxNDgwYTgyMTU0MTViZjRiY2U2NmM5OQ==
4
+ NDM1MWIwOWZmYThlZjA5YTJlMzdlZDM3MDQzMjg5ZGNlOTVhOGYxMQ==
5
5
  data.tar.gz: !binary |-
6
- Mzk1MjM1MTZhNDcyMTNlY2I2OTMzZTljOTU1NWJmMmU5MTE4Yjg3NQ==
6
+ ODgwMDMwMDM3M2MyZTdjN2YwZDBhMDlhMDJlZTY5MzcwZTVhMjVjNQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- OWI4ZWFhZDljMDNhMjgzYWVkNTQ5NDVhZmMzMjhmN2JhMTdiNDNlZjVkZjc4
10
- NjNmNDRjMDg3MmJiMTg1YThiN2YzNTMwMTBhMGQxMGYxMGMzZWFhZmQ2MjU2
11
- N2YwMDhlZjg1NTU2NzI5YTc0NmUzNWZhNTBmOTdhY2NiNDg1N2E=
9
+ OGIyY2JkM2Y5OTI4NzdmZDk5OTE2ZGM4OWU4ZTM3MTYzOWNhMGRlOWZlNTc4
10
+ ZTcxODBmYzMxYjdmNDJkNGFhZDc0NGQzZGE3ODU0NTE4ODliYjQ4MTIyMGJi
11
+ NjBjMTE3ZGE1ZDM5Y2QwYWVjNTgwZDQxOGRkNDc0OTRhYzA2YjQ=
12
12
  data.tar.gz: !binary |-
13
- ZDY3NzU2MmFhZTJjN2I3MWQ1ODgzNGYyZTAwMDZhNTlhYTdmYTNkMjNjOWFi
14
- MjMzMjliMjMxNWY1NGRlNzBmZDMxYTQ1YjIwMjgzOTg5NGRkM2MzNzhjNDRk
15
- ZmJiYzdmZWE4YjA0ZGJmMTIxOTc3ZjNkMmUyMmI2NGZkODRhYzY=
13
+ M2ZlYmU3ZGE5ZjBkNDkxYjgyZWFlZmM4OWEyYjMxYzYzMmI1ODAyOTFhMmM1
14
+ ZDk0ZDA1YWUxODY2NGIzZDEwMTdiODQ5MWJkN2NlYjFlMTc5YjAxZmVkYzY1
15
+ NjY3YWY4NGIyNGFkNzMxNmZmY2E2YmJkOTIyNWZjMjU3MjZhNTE=
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
  gemspec
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Rémi Prévost
1
+ Copyright (c) 2012-2013 Rémi Prévost
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
data/README.md CHANGED
@@ -261,12 +261,12 @@ end
261
261
 
262
262
  Here’s a list of several useful features available in Her.
263
263
 
264
- ### Relationships
264
+ ### Associations
265
265
 
266
- You can define `has_many`, `has_one` and `belongs_to` relationships in your models. The relationship data is handled in two different ways.
266
+ You can define `has_many`, `has_one` and `belongs_to` associations in your models. The association data is handled in two different ways.
267
267
 
268
- 1. If Her finds relationship data when parsing a resource, that data will be used to create the associated model objects on the resource.
269
- 2. If no relationship data was included when parsing a resource, calling a method with the same name as the relationship will fetch the data (providing there’s an HTTP request available for it in the API).
268
+ 1. If Her finds association data when parsing a resource, that data will be used to create the associated model objects on the resource.
269
+ 2. If no association data was included when parsing a resource, calling a method with the same name as the association will fetch the data (providing there’s an HTTP request available for it in the API).
270
270
 
271
271
  For example:
272
272
 
@@ -291,7 +291,7 @@ class Organization
291
291
  end
292
292
  ```
293
293
 
294
- If there’s relationship data in the resource, no extra HTTP request is made when calling the `#comments` method and an array of resources is returned:
294
+ If there’s association data in the resource, no extra HTTP request is made when calling the `#comments` method and an array of resources is returned:
295
295
 
296
296
  ```ruby
297
297
  @user = User.find(1)
@@ -315,23 +315,23 @@ If there’s relationship data in the resource, no extra HTTP request is made wh
315
315
  # #<Organization id=2 name="Bluth Company">
316
316
  ```
317
317
 
318
- If there’s no relationship data in the resource, Her makes a HTTP request to retrieve the data.
318
+ If there’s no association data in the resource, Her makes a HTTP request to retrieve the data.
319
319
 
320
320
  ```ruby
321
321
  @user = User.find(1)
322
322
  # { :data => { :id => 1, :name => "George Michael Bluth", :organization_id => 2 }}
323
323
 
324
- # has_many relationship:
324
+ # has_many association:
325
325
  @user.comments
326
326
  # GET /users/1/comments
327
327
  # [#<Comment id=1>, #<Comment id=2>]
328
328
 
329
- # has_one relationship:
329
+ # has_one association:
330
330
  @user.role
331
331
  # GET /users/1/role
332
332
  # #<Role id=1>
333
333
 
334
- # belongs_to relationship:
334
+ # belongs_to association:
335
335
  @user.organization
336
336
  # (the organization id comes from :organization_id, by default)
337
337
  # GET /organizations/2
@@ -365,7 +365,6 @@ end
365
365
  ### Dirty attributes
366
366
 
367
367
  Her includes `ActiveModel::Dirty` so you can keep track of the attributes that have changed in an object.
368
- an object, or `#create` on a model class.
369
368
 
370
369
  ```ruby
371
370
  class User
data/lib/her/api.rb CHANGED
@@ -7,8 +7,8 @@ module Her
7
7
 
8
8
  # Setup a default API connection. Accepted arguments and options are the same as {API#setup}.
9
9
  def self.setup(attrs={}, &block)
10
- @@default_api = new
11
- @@default_api.setup(attrs, &block)
10
+ @default_api = new
11
+ @default_api.setup(attrs, &block)
12
12
  end
13
13
 
14
14
  # Create a new API object. This is useful to create multiple APIs and use them with the `uses_api` method.
@@ -103,7 +103,7 @@ module Her
103
103
  private
104
104
  # @private
105
105
  def self.default_api(attrs={})
106
- defined?(@@default_api) ? @@default_api : nil
106
+ defined?(@default_api) ? @default_api : nil
107
107
  end
108
108
  end
109
109
  end
data/lib/her/errors.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Her
2
2
  module Errors
3
3
  class PathError < StandardError; end;
4
- class RelationshipUnknownError < StandardError; end;
4
+ class AssociationUnknownError < StandardError; end;
5
5
  end
6
6
  end
data/lib/her/model.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "her/model/base"
2
2
  require "her/model/http"
3
3
  require "her/model/orm"
4
- require "her/model/relationships"
4
+ require "her/model/associations"
5
5
  require "her/model/introspection"
6
6
  require "her/model/paths"
7
7
  require "her/model/nested_attributes"
@@ -25,7 +25,7 @@ module Her
25
25
  include Her::Model::ORM
26
26
  include Her::Model::Introspection
27
27
  include Her::Model::Paths
28
- include Her::Model::Relationships
28
+ include Her::Model::Associations
29
29
  include Her::Model::NestedAttributes
30
30
  include ActiveModel::Validations
31
31
  include ActiveModel::Conversion
@@ -51,18 +51,18 @@ module Her
51
51
 
52
52
  # Returns true if attribute_name is
53
53
  # * in orm data
54
- # * a relationship
54
+ # * an association
55
55
  def has_key?(attribute_name)
56
56
  has_data?(attribute_name) ||
57
- has_relationship?(attribute_name)
57
+ has_association?(attribute_name)
58
58
  end
59
59
 
60
60
  # Returns
61
61
  # * the value of the attribute_nane attribute if it's in orm data
62
- # * the resource/collection corrsponding to attribute_name if it's a relationship
62
+ # * the resource/collection corrsponding to attribute_name if it's an association
63
63
  def [](attribute_name)
64
64
  get_data(attribute_name) ||
65
- get_relationship(attribute_name)
65
+ get_association(attribute_name)
66
66
  end
67
67
  end
68
68
  end
@@ -1,49 +1,55 @@
1
1
  module Her
2
2
  module Model
3
- # This module adds relationships to models
4
- module Relationships
3
+ # This module adds associations to models
4
+ module Associations
5
5
  extend ActiveSupport::Concern
6
6
 
7
- # Returns true if the model has a relationship_name relationship, false otherwise.
8
- def has_relationship?(relationship_name)
9
- relationships = self.class.relationships.values.flatten.map { |r| r[:name] }
10
- relationships.include?(relationship_name)
7
+ # Returns true if the model has a association_name association, false otherwise.
8
+ def has_association?(association_name)
9
+ associations = self.class.associations.values.flatten.map { |r| r[:name] }
10
+ associations.include?(association_name)
11
11
  end
12
+ alias :has_relationship? :has_association?
12
13
 
13
- # Returns the resource/collection corresponding to the relationship_name relationship.
14
- def get_relationship(relationship_name)
15
- send(relationship_name) if has_relationship?(relationship_name)
14
+ # Returns the resource/collection corresponding to the association_name association.
15
+ def get_association(association_name)
16
+ send(association_name) if has_association?(association_name)
16
17
  end
18
+ alias :get_relationship :get_association
17
19
 
18
20
  module ClassMethods
19
- # Return @her_relationships, lazily initialized with copy of the
20
- # superclass' her_relationships, or an empty hash.
21
+ # Return @her_associations, lazily initialized with copy of the
22
+ # superclass' her_associations, or an empty hash.
21
23
  #
22
24
  # @private
23
- def relationships
24
- @her_relationships ||= begin
25
- if superclass.respond_to?(:relationships)
26
- superclass.relationships.dup
25
+ def associations
26
+ @her_associations ||= begin
27
+ if superclass.respond_to?(:associations)
28
+ superclass.associations.dup
27
29
  else
28
30
  {}
29
31
  end
30
32
  end
31
33
  end
34
+ alias :relationships :associations
32
35
 
33
- # Parse relationships data after initializing a new object
36
+ # Parse associations data after initializing a new object
34
37
  #
35
38
  # @private
36
- def parse_relationships(data)
37
- relationships.each_pair do |type, definitions|
38
- definitions.each do |relationship|
39
- name = relationship[:name]
40
- next unless data[name]
41
- klass = self.nearby_class(relationship[:class_name])
39
+ def parse_associations(data)
40
+ associations.each_pair do |type, definitions|
41
+ definitions.each do |association|
42
+ data_key = association[:data_key]
43
+ next unless data[data_key]
44
+
45
+ klass = self.nearby_class(association[:class_name])
46
+ name = association[:name]
47
+
42
48
  data[name] = case type
43
49
  when :has_many
44
- Her::Model::ORM.initialize_collection(klass, :data => data[name])
50
+ Her::Model::ORM.initialize_collection(klass, :data => data[data_key])
45
51
  when :has_one, :belongs_to
46
- klass.new(klass.parse(data[name]))
52
+ klass.new(data[data_key])
47
53
  else
48
54
  nil
49
55
  end
@@ -52,7 +58,7 @@ module Her
52
58
  data
53
59
  end
54
60
 
55
- # Define an *has_many* relationship.
61
+ # Define an *has_many* association.
56
62
  #
57
63
  # @param [Symbol] name The name of the model
58
64
  # @param [Hash] attrs Options (currently not used)
@@ -74,34 +80,39 @@ module Her
74
80
  attrs = {
75
81
  :class_name => name.to_s.classify,
76
82
  :name => name,
83
+ :data_key => name,
77
84
  :path => "/#{name}",
78
85
  :inverse_of => nil
79
86
  }.merge(attrs)
80
- (relationships[:has_many] ||= []) << attrs
87
+ (associations[:has_many] ||= []) << attrs
81
88
 
82
89
  define_method(name) do |*method_attrs|
83
90
  method_attrs = method_attrs[0] || {}
84
91
  klass = self.class.nearby_class(attrs[:class_name])
85
- if method_attrs.any?
86
- @data[name] = klass.get_collection("#{self.class.build_request_path(method_attrs.merge(:id => id))}#{attrs[:path]}", method_attrs)
87
- else
88
- @data[name] ||= klass.get_collection("#{self.class.build_request_path(:id => id)}#{attrs[:path]}")
92
+
93
+ return Her::Collection.new if @attributes.include?(name) && @attributes[name].empty? && method_attrs.empty?
94
+
95
+ if @attributes[name].blank? || method_attrs.any?
96
+ path = begin
97
+ self.class.build_request_path(@attributes.merge(method_attrs))
98
+ rescue Her::Errors::PathError
99
+ return nil
100
+ end
101
+
102
+ @attributes[name] = klass.get_collection("#{path}#{attrs[:path]}", method_attrs)
89
103
  end
90
104
 
91
- inverse_of = if attrs[:inverse_of]
92
- attrs[:inverse_of]
93
- else
94
- self.class.name.split('::').last.tableize.singularize
95
- end
96
- @data[name].each do |entry|
105
+ inverse_of = attrs[:inverse_of] || self.class.name.split('::').last.tableize.singularize
106
+
107
+ @attributes[name].each do |entry|
97
108
  entry.send("#{inverse_of}=", self)
98
109
  end
99
110
 
100
- @data[name]
111
+ @attributes[name]
101
112
  end
102
113
  end
103
114
 
104
- # Define an *has_one* relationship.
115
+ # Define an *has_one* association.
105
116
  #
106
117
  # @param [Symbol] name The name of the model
107
118
  # @param [Hash] attrs Options (currently not used)
@@ -123,22 +134,32 @@ module Her
123
134
  attrs = {
124
135
  :class_name => name.to_s.classify,
125
136
  :name => name,
137
+ :data_key => name,
126
138
  :path => "/#{name}"
127
139
  }.merge(attrs)
128
- (relationships[:has_one] ||= []) << attrs
140
+ (associations[:has_one] ||= []) << attrs
129
141
 
130
142
  define_method(name) do |*method_attrs|
131
143
  method_attrs = method_attrs[0] || {}
132
144
  klass = self.class.nearby_class(attrs[:class_name])
133
- if method_attrs.any?
134
- klass.get_resource("#{self.class.build_request_path(method_attrs.merge(:id => id))}#{attrs[:path]}", method_attrs)
135
- else
136
- @data[name] ||= klass.get_resource("#{self.class.build_request_path(:id => id)}#{attrs[:path]}")
145
+
146
+ return nil if @attributes.include?(name) && @attributes[name].nil? && method_attrs.empty?
147
+
148
+ if @attributes[name].blank? || method_attrs.any?
149
+ path = begin
150
+ self.class.build_request_path(@attributes.merge(method_attrs))
151
+ rescue Her::Errors::PathError
152
+ return nil
153
+ end
154
+
155
+ @attributes[name] = klass.get_resource("#{path}#{attrs[:path]}", method_attrs)
137
156
  end
157
+
158
+ @attributes[name]
138
159
  end
139
160
  end
140
161
 
141
- # Define a *belongs_to* relationship.
162
+ # Define a *belongs_to* association.
142
163
  #
143
164
  # @param [Symbol] name The name of the model
144
165
  # @param [Hash] attrs Options (currently not used)
@@ -160,29 +181,29 @@ module Her
160
181
  attrs = {
161
182
  :class_name => name.to_s.classify,
162
183
  :name => name,
184
+ :data_key => name,
163
185
  :foreign_key => "#{name}_id",
164
186
  :path => "/#{name.to_s.pluralize}/:id"
165
187
  }.merge(attrs)
166
- (relationships[:belongs_to] ||= []) << attrs
188
+ (associations[:belongs_to] ||= []) << attrs
167
189
 
168
190
  define_method(name) do |*method_attrs|
169
191
  method_attrs = method_attrs[0] || {}
170
192
  klass = self.class.nearby_class(attrs[:class_name])
171
- if method_attrs.any?
172
- klass.get_resource("#{klass.build_request_path(method_attrs.merge(:id => @data[attrs[:foreign_key].to_sym]))}", method_attrs)
173
- else
174
- @data[name] ||= klass.get_resource("#{klass.build_request_path(:id => @data[attrs[:foreign_key].to_sym])}")
193
+
194
+ return nil if @attributes.include?(name) && @attributes[name].nil? && method_attrs.empty?
195
+
196
+ if @attributes[name].blank? || method_attrs.any?
197
+ path = begin
198
+ klass.build_request_path(@attributes.merge(method_attrs.merge(:id => @attributes[attrs[:foreign_key].to_sym])))
199
+ rescue Her::Errors::PathError
200
+ return nil
201
+ end
202
+
203
+ @attributes[name] = klass.get_resource("#{path}", method_attrs)
175
204
  end
176
- end
177
- end
178
205
 
179
- # @private
180
- def relationship_accessor(type, attrs)
181
- name = attrs[:name]
182
- class_name = attrs[:class_name]
183
- define_method(name) do
184
- klass = self.class.nearby_class(attrs[:class_name])
185
- @data[name] ||= klass.get_resource("#{klass.build_request_path(attrs[:path], :id => @data[attrs[:foreign_key].to_sym])}")
206
+ @attributes[name]
186
207
  end
187
208
  end
188
209
  end
@@ -12,7 +12,7 @@ module Her
12
12
  # @user = User.find(1)
13
13
  # p @user # => #<User(/users/1) id=1 name="Tobias Fünke">
14
14
  def inspect
15
- "#<#{self.class}(#{request_path}) #{@data.keys.map { |k| "#{k}=#{attribute_for_inspect(send(k))}" }.join(" ")}>"
15
+ "#<#{self.class}(#{request_path}) #{attributes.keys.map { |k| "#{k}=#{attribute_for_inspect(send(k))}" }.join(" ")}>"
16
16
  end
17
17
 
18
18
  private
@@ -4,52 +4,52 @@ module Her
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  module ClassMethods
7
- def accepts_nested_attributes_for(*relationship_names)
8
- relationship_names.each do |relationship_name|
7
+ def accepts_nested_attributes_for(*association_names)
8
+ association_names.each do |association_name|
9
9
  type = nil
10
- [:belongs_to, :has_one, :has_many].each do |relation_type|
11
- if !relationships[relation_type].nil? && relationships[relation_type].any? { |relation| relation[:name] == relationship_name }
12
- type = relation_type
10
+ [:belongs_to, :has_one, :has_many].each do |association_type|
11
+ if !associations[association_type].nil? && associations[association_type].any? { |association| association[:name] == association_name }
12
+ type = association_type
13
13
  end
14
14
  end
15
15
  if type.nil?
16
- raise(RelationshipUnknownError.new("Unknown relationship name :#{relationship_name}"))
16
+ raise(AssociationUnknownError.new("Unknown association name :#{association_name}"))
17
17
  end
18
18
  class_eval <<-eoruby, __FILE__, __LINE__ + 1
19
- if method_defined?(:#{relationship_name}_attributes=)
20
- remove_method(:#{relationship_name}_attributes=)
19
+ if method_defined?(:#{association_name}_attributes=)
20
+ remove_method(:#{association_name}_attributes=)
21
21
  end
22
- def #{relationship_name}_attributes=(attributes)
23
- assign_nested_attributes_for_#{type}_relationship(:#{relationship_name}, attributes)
22
+ def #{association_name}_attributes=(attributes)
23
+ assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
24
24
  end
25
25
  eoruby
26
26
  end
27
27
  end
28
28
  end
29
29
 
30
- def assign_nested_attributes_for_belongs_to_relationship(relationship_name, attributes)
31
- assign_nested_attributes_for_simple_relationship(:belongs_to, relationship_name, attributes)
30
+ def assign_nested_attributes_for_belongs_to_association(association_name, attributes)
31
+ assign_nested_attributes_for_simple_association(:belongs_to, association_name, attributes)
32
32
  end
33
33
 
34
- def assign_nested_attributes_for_has_one_relationship(relationship_name, attributes)
35
- assign_nested_attributes_for_simple_relationship(:has_one, relationship_name, attributes)
34
+ def assign_nested_attributes_for_has_one_association(association_name, attributes)
35
+ assign_nested_attributes_for_simple_association(:has_one, association_name, attributes)
36
36
  end
37
37
 
38
- def assign_nested_attributes_for_has_many_relationship(relationship_name, attributes)
39
- relationship = self.class.relationships[:has_many].find { |relation| relation[:name] == relationship_name }
40
- klass = self.class.nearby_class(relationship[:class_name])
41
- self.send("#{relationship[:name]}=", Her::Model::ORM.initialize_collection(klass, :data => attributes))
38
+ def assign_nested_attributes_for_has_many_association(association_name, attributes)
39
+ association = self.class.associations[:has_many].find { |association| association[:name] == association_name }
40
+ klass = self.class.nearby_class(association[:class_name])
41
+ self.send("#{association[:name]}=", Her::Model::ORM.initialize_collection(klass, :data => attributes))
42
42
  end
43
43
 
44
44
  private
45
- def assign_nested_attributes_for_simple_relationship(relationship_type, relationship_name, attributes)
46
- relationship = self.class.relationships[relationship_type].find { |relation| relation[:name] == relationship_name }
47
- if has_data?(relationship[:name])
48
- self.send("#{relationship[:name]}").assign_data(attributes)
45
+ def assign_nested_attributes_for_simple_association(association_type, association_name, attributes)
46
+ association = self.class.associations[association_type].find { |association| association[:name] == association_name }
47
+ if has_data?(association[:name])
48
+ self.send("#{association[:name]}").assign_data(attributes)
49
49
  else
50
- klass = self.class.nearby_class(relationship[:class_name])
50
+ klass = self.class.nearby_class(association[:class_name])
51
51
  instance = klass.new(klass.parse(attributes))
52
- self.send("#{relationship[:name]}=", instance)
52
+ self.send("#{association[:name]}=", instance)
53
53
  end
54
54
  end
55
55
  end
data/lib/her/model/orm.rb CHANGED
@@ -3,17 +3,18 @@ module Her
3
3
  # This module adds ORM-like capabilities to the model
4
4
  module ORM
5
5
  extend ActiveSupport::Concern
6
- attr_accessor :data, :metadata, :response_errors
7
- alias :attributes :data
8
- alias :attributes= :data=
6
+ attr_accessor :attributes, :metadata, :response_errors
7
+ alias :data :attributes
8
+ alias :data= :attributes=
9
9
 
10
10
  # Initialize a new object with data received from an HTTP request
11
- def initialize(params={})
12
- @metadata = params.delete(:_metadata) || {}
13
- @response_errors = params.delete(:_errors) || {}
14
- @destroyed = params.delete(:_destroyed) || false
11
+ def initialize(attributes={})
12
+ attributes ||= {}
13
+ @metadata = attributes.delete(:_metadata) || {}
14
+ @response_errors = attributes.delete(:_errors) || {}
15
+ @destroyed = attributes.delete(:_destroyed) || false
15
16
 
16
- update_data(params)
17
+ update_attributes(attributes)
17
18
  end
18
19
 
19
20
  # Initialize a collection of resources
@@ -32,6 +33,7 @@ module Her
32
33
  # @private
33
34
  def self.use_setter_methods(model, params)
34
35
  setter_method_names = model.class.setter_method_names
36
+ params ||= {}
35
37
  params.inject({}) do |memo, (key, value)|
36
38
  setter_method = key.to_s + '='
37
39
  if setter_method_names.include?(setter_method)
@@ -46,16 +48,18 @@ module Her
46
48
  end
47
49
  end
48
50
 
49
- # Handles missing methods by routing them through @data
51
+ # Handles missing methods
50
52
  # @private
51
53
  def method_missing(method, *args, &blk)
52
- if method.to_s.end_with?('=')
53
- attribute = method.to_s.chomp('=').to_sym
54
- @data[attribute] = args.first
55
- elsif method.to_s.end_with?('?')
56
- @data.include?(method.to_s.chomp('?').to_sym)
57
- elsif @data.include?(method)
58
- @data[method]
54
+ if method.to_s =~ /[?=]$/ || attributes.include?(method)
55
+ # Extract the attribute
56
+ attribute = method.to_s.sub(/[?=]$/, '')
57
+
58
+ # Create a new `attribute` methods set
59
+ self.class.attributes(*attribute)
60
+
61
+ # Resend the method!
62
+ send(method, *args, &blk)
59
63
  else
60
64
  super
61
65
  end
@@ -63,44 +67,45 @@ module Her
63
67
 
64
68
  # Handles returning true for the cases handled by method_missing
65
69
  def respond_to?(method, include_private = false)
66
- method.to_s.end_with?('=') || method.to_s.end_with?('?') || @data.include?(method) || super
70
+ method.to_s.end_with?('=') || method.to_s.end_with?('?') || @attributes.include?(method) || super
67
71
  end
68
72
 
69
73
  def respond_to_missing?(method, include_private = false)
70
- method.to_s.end_with?('=') || method.to_s.end_with?('?') || @data.include?(method) || @data.include?(method) || super
74
+ method.to_s.end_with?('=') || method.to_s.end_with?('?') || @attributes.include?(method) || @attributes.include?(method) || super
71
75
  end
72
76
 
73
77
  # Assign new data to an instance
74
- def assign_data(new_data)
75
- new_data = Her::Model::ORM.use_setter_methods(self, new_data)
76
- @data.update new_data
78
+ def assign_attributes(new_attributes)
79
+ new_attributes = Her::Model::ORM.use_setter_methods(self, new_attributes)
80
+ attributes.update new_attributes
77
81
  end
78
- alias :assign_attributes :assign_data
82
+ alias :assign_data :assign_attributes
79
83
 
80
84
  # Handles returning true for the accessible attributes
81
- def has_data?(attribute_name)
82
- @data.include?(attribute_name)
85
+ def has_attribute?(attribute_name)
86
+ attributes.include?(attribute_name)
83
87
  end
88
+ alias :has_data? :has_attribute?
84
89
 
85
- # Handles returning attribute value from data
86
- def get_data(attribute_name)
87
- @data[attribute_name]
90
+ def get_attribute(attribute_name)
91
+ attributes[attribute_name]
88
92
  end
93
+ alias :get_data :get_attribute
89
94
 
90
95
  # Override the method to prevent from returning the object ID (in ruby-1.8.7)
91
96
  # @private
92
97
  def id
93
- @data[:id] || super
98
+ attributes[:id] || super
94
99
  end
95
100
 
96
101
  # Return `true` if a resource was not saved yet
97
102
  def new?
98
- !@data.include?(:id)
103
+ !attributes.include?(:id)
99
104
  end
100
105
 
101
106
  # Return `true` if the other object is also a Her::Model and has matching data
102
107
  def ==(other)
103
- other.is_a?(Her::Model) && @data == other.data
108
+ other.is_a?(Her::Model) && attributes == other.attributes
104
109
  end
105
110
 
106
111
  # Delegate to the == method
@@ -108,10 +113,10 @@ module Her
108
113
  self == other
109
114
  end
110
115
 
111
- # Delegate to @data, allowing models to act correctly in code like:
116
+ # Delegate to @attributes, allowing models to act correctly in code like:
112
117
  # [ Model.find(1), Model.find(1) ].uniq # => [ Model.find(1) ]
113
118
  def hash
114
- @data.hash
119
+ attributes.hash
115
120
  end
116
121
 
117
122
  # Return whether the object has been destroyed
@@ -136,7 +141,7 @@ module Her
136
141
  params = to_params
137
142
  resource = self
138
143
 
139
- if @data[:id]
144
+ if attributes[:id]
140
145
  callback = :update
141
146
  method = :put
142
147
  else
@@ -147,12 +152,12 @@ module Her
147
152
  run_callbacks callback do
148
153
  run_callbacks :save do
149
154
  self.class.request(params.merge(:_method => method, :_path => "#{request_path}")) do |parsed_data, response|
150
- update_data(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
155
+ update_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
151
156
  self.metadata = parsed_data[:metadata]
152
157
  self.response_errors = parsed_data[:errors]
153
158
  self.changed_attributes.clear if self.changed_attributes.present?
154
159
 
155
- return false if self.response_errors.any?
160
+ return false if !response.success? || self.response_errors.any?
156
161
  end
157
162
  end
158
163
  end
@@ -170,7 +175,7 @@ module Her
170
175
  resource = self
171
176
  run_callbacks :destroy do
172
177
  self.class.request(:_method => :delete, :_path => "#{request_path}") do |parsed_data, response|
173
- update_data(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
178
+ update_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
174
179
  self.metadata = parsed_data[:metadata]
175
180
  self.response_errors = parsed_data[:errors]
176
181
  @destroyed = true
@@ -180,13 +185,13 @@ module Her
180
185
  end
181
186
 
182
187
  # @private
183
- def update_data(raw_data)
184
- @data ||= {}
185
- # Use setter methods first, then translate attributes of relationships
186
- # into relationship instances, then merge the parsed_data into @data.
187
- unset_data = Her::Model::ORM.use_setter_methods(self, raw_data)
188
- parsed_data = self.class.parse_relationships(unset_data)
189
- @data.update(parsed_data)
188
+ def update_attributes(raw_data)
189
+ @attributes ||= {}
190
+ # Use setter methods first, then translate attributes of associations
191
+ # into association instances, then merge the parsed_data into @attributes.
192
+ unset_attributes = Her::Model::ORM.use_setter_methods(self, raw_data)
193
+ parsed_attributes = self.class.parse_associations(unset_attributes)
194
+ attributes.update(parsed_attributes)
190
195
  end
191
196
 
192
197
  # Convert into a hash of request parameters
@@ -196,9 +201,9 @@ module Her
196
201
  # # => { :id => 1, :name => 'John Smith' }
197
202
  def to_params
198
203
  if self.class.include_root_in_json
199
- { (self.class.include_root_in_json == true ? self.class.root_element : self.class.include_root_in_json) => @data.dup }
204
+ { (self.class.include_root_in_json == true ? self.class.root_element : self.class.include_root_in_json) => attributes.dup }
200
205
  else
201
- @data.dup
206
+ attributes.dup
202
207
  end
203
208
  end
204
209
 
@@ -220,16 +225,16 @@ module Her
220
225
  attribute = attribute.to_sym
221
226
 
222
227
  define_method "#{attribute}".to_sym do
223
- @data.include?(attribute) ? @data[attribute] : nil
228
+ @attributes.include?(attribute) ? @attributes[attribute] : nil
224
229
  end
225
230
 
226
231
  define_method "#{attribute}=".to_sym do |value|
227
- self.send("#{attribute}_will_change!".to_sym) if @data[attribute] != value
228
- @data[attribute] = value
232
+ self.send("#{attribute}_will_change!".to_sym) if @attributes[attribute] != value
233
+ @attributes[attribute] = value
229
234
  end
230
235
 
231
236
  define_method "#{attribute}?".to_sym do
232
- @data.include?(attribute)
237
+ @attributes.include?(attribute) && @attributes[attribute].present?
233
238
  end
234
239
  end
235
240
  end
@@ -299,7 +304,7 @@ module Her
299
304
  request(params.merge(:_method => :post, :_path => "#{build_request_path(params)}")) do |parsed_data, response|
300
305
  data = parse(parsed_data[:data])
301
306
  resource.instance_eval do
302
- update_data(data)
307
+ update_attributes(data)
303
308
  @metadata = parsed_data[:metadata]
304
309
  @response_errors = parsed_data[:errors]
305
310
  @changed_attributes.clear if @changed_attributes.present?
@@ -12,7 +12,7 @@ module Her
12
12
  #
13
13
  # User.find(1) # Fetched via GET /utilisateurs/1
14
14
  def request_path
15
- self.class.build_request_path(@data.dup)
15
+ self.class.build_request_path(attributes.dup)
16
16
  end
17
17
 
18
18
  module ClassMethods
@@ -67,7 +67,7 @@ module Her
67
67
 
68
68
  path.gsub(/:([\w_]+)/) do
69
69
  # Look for :key or :_key, otherwise raise an exception
70
- parameters.delete($1.to_sym) || parameters.delete("_#{$1}".to_sym) || raise(Her::Errors::PathError.new("Missing :_#{$1} parameter to build the request path (#{path})."))
70
+ parameters.delete($1.to_sym) || parameters.delete("_#{$1}".to_sym) || raise(Her::Errors::PathError, "Missing :_#{$1} parameter to build the request path. Path is `#{path}`. Parameters are `#{parameters.inspect}`.")
71
71
  end
72
72
  end
73
73
 
data/lib/her/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.2"
3
3
  end
@@ -1,100 +1,100 @@
1
1
  # encoding: utf-8
2
2
  require File.join(File.dirname(__FILE__), "../spec_helper.rb")
3
3
 
4
- describe Her::Model::Relationships do
5
- context "setting relationships without details" do
4
+ describe Her::Model::Associations do
5
+ context "setting associations without details" do
6
6
  before do
7
7
  spawn_model "Foo::User"
8
8
  end
9
9
 
10
- it "handles a single 'has_many' relationship" do
10
+ it "handles a single 'has_many' association" do
11
11
  Foo::User.has_many :comments
12
- Foo::User.relationships[:has_many].should == [{ :name => :comments, :class_name => "Comment", :path => "/comments", :inverse_of => nil }]
12
+ Foo::User.associations[:has_many].should == [{ :name => :comments, :data_key => :comments, :class_name => "Comment", :path => "/comments", :inverse_of => nil }]
13
13
  end
14
14
 
15
- it "handles multiples 'has_many' relationship" do
15
+ it "handles multiples 'has_many' association" do
16
16
  Foo::User.has_many :comments
17
17
  Foo::User.has_many :posts
18
- Foo::User.relationships[:has_many].should == [{ :name => :comments, :class_name => "Comment", :path => "/comments", :inverse_of => nil }, { :name => :posts, :class_name => "Post", :path => "/posts", :inverse_of => nil }]
18
+ Foo::User.associations[:has_many].should == [{ :name => :comments, :data_key => :comments, :class_name => "Comment", :path => "/comments", :inverse_of => nil }, { :name => :posts, :data_key => :posts, :class_name => "Post", :path => "/posts", :inverse_of => nil }]
19
19
  end
20
20
 
21
- it "handles a single 'has_one' relationship" do
21
+ it "handles a single 'has_one' association" do
22
22
  Foo::User.has_one :category
23
- Foo::User.relationships[:has_one].should == [{ :name => :category, :class_name => "Category", :path => "/category" }]
23
+ Foo::User.associations[:has_one].should == [{ :name => :category, :data_key => :category, :class_name => "Category", :path => "/category" }]
24
24
  end
25
25
 
26
- it "handles multiples 'has_one' relationship" do
26
+ it "handles multiples 'has_one' association" do
27
27
  Foo::User.has_one :category
28
28
  Foo::User.has_one :role
29
- Foo::User.relationships[:has_one].should == [{ :name => :category, :class_name => "Category", :path => "/category" }, { :name => :role, :class_name => "Role", :path => "/role" }]
29
+ Foo::User.associations[:has_one].should == [{ :name => :category, :data_key => :category, :class_name => "Category", :path => "/category" }, { :name => :role, :data_key => :role, :class_name => "Role", :path => "/role" }]
30
30
  end
31
31
 
32
- it "handles a single belongs_to relationship" do
32
+ it "handles a single belongs_to association" do
33
33
  Foo::User.belongs_to :organization
34
- Foo::User.relationships[:belongs_to].should == [{ :name => :organization, :class_name => "Organization", :foreign_key => "organization_id", :path => "/organizations/:id" }]
34
+ Foo::User.associations[:belongs_to].should == [{ :name => :organization, :data_key => :organization, :class_name => "Organization", :foreign_key => "organization_id", :path => "/organizations/:id" }]
35
35
  end
36
36
 
37
- it "handles multiples 'belongs_to' relationship" do
37
+ it "handles multiples 'belongs_to' association" do
38
38
  Foo::User.belongs_to :organization
39
39
  Foo::User.belongs_to :family
40
- Foo::User.relationships[:belongs_to].should == [{ :name => :organization, :class_name => "Organization", :foreign_key => "organization_id", :path => "/organizations/:id" }, { :name => :family, :class_name => "Family", :foreign_key => "family_id", :path => "/families/:id" }]
40
+ Foo::User.associations[:belongs_to].should == [{ :name => :organization, :data_key => :organization, :class_name => "Organization", :foreign_key => "organization_id", :path => "/organizations/:id" }, { :name => :family, :data_key => :family, :class_name => "Family", :foreign_key => "family_id", :path => "/families/:id" }]
41
41
  end
42
42
  end
43
43
 
44
- context "setting relationships with details" do
44
+ context "setting associations with details" do
45
45
  before do
46
46
  spawn_model "Foo::User"
47
47
  end
48
48
 
49
- it "handles a single 'has_many' relationship" do
50
- Foo::User.has_many :comments, :class_name => "Post", :inverse_of => :admin
51
- Foo::User.relationships[:has_many].should == [{ :name => :comments, :class_name => "Post", :path => "/comments", :inverse_of => :admin }]
49
+ it "handles a single 'has_many' association" do
50
+ Foo::User.has_many :comments, :class_name => "Post", :inverse_of => :admin, :data_key => :user_comments
51
+ Foo::User.associations[:has_many].should == [{ :name => :comments, :data_key => :user_comments, :class_name => "Post", :path => "/comments", :inverse_of => :admin }]
52
52
  end
53
53
 
54
- it "handles a single 'has_one' relationship" do
55
- Foo::User.has_one :category, :class_name => "Topic", :foreign_key => "topic_id"
56
- Foo::User.relationships[:has_one].should == [{ :name => :category, :class_name => "Topic", :foreign_key => "topic_id", :path => "/category" }]
54
+ it "handles a single 'has_one' association" do
55
+ Foo::User.has_one :category, :class_name => "Topic", :foreign_key => "topic_id", :data_key => :topic
56
+ Foo::User.associations[:has_one].should == [{ :name => :category, :data_key => :topic, :class_name => "Topic", :foreign_key => "topic_id", :path => "/category" }]
57
57
  end
58
58
 
59
- it "handles a single belongs_to relationship" do
60
- Foo::User.belongs_to :organization, :class_name => "Business", :foreign_key => "org_id"
61
- Foo::User.relationships[:belongs_to].should == [{ :name => :organization, :class_name => "Business", :foreign_key => "org_id", :path => "/organizations/:id" }]
59
+ it "handles a single belongs_to association" do
60
+ Foo::User.belongs_to :organization, :class_name => "Business", :foreign_key => "org_id", :data_key => :org
61
+ Foo::User.associations[:belongs_to].should == [{ :name => :organization, :data_key => :org, :class_name => "Business", :foreign_key => "org_id", :path => "/organizations/:id" }]
62
62
  end
63
63
 
64
- context "inheriting relationships from a superclass" do
65
- it "copies relationships to the subclass" do
64
+ context "inheriting associations from a superclass" do
65
+ it "copies associations to the subclass" do
66
66
  Foo::User.has_many :comments, :class_name => "Post"
67
67
  subclass = Class.new(Foo::User)
68
- subclass.relationships.object_id.should_not == Foo::User.relationships.object_id
69
- subclass.relationships[:has_many].length.should == 1
70
- subclass.relationships[:has_many].first[:class_name].should == "Post"
68
+ subclass.associations.object_id.should_not == Foo::User.associations.object_id
69
+ subclass.associations[:has_many].length.should == 1
70
+ subclass.associations[:has_many].first[:class_name].should == "Post"
71
71
  end
72
72
  end
73
73
  end
74
74
 
75
- context "handling relationships without details" do
75
+ context "handling associations without details" do
76
76
  before do
77
77
  Her::API.setup :url => "https://api.example.com" do |builder|
78
78
  builder.use Her::Middleware::FirstLevelParseJSON
79
79
  builder.use Faraday::Request::UrlEncoded
80
80
  builder.adapter :test do |stub|
81
- stub.get("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke", :comments => [{ :id => 2, :body => "Tobias, you blow hard!", :user_id => 1 }, { :id => 3, :body => "I wouldn't mind kissing that man between the cheeks, so to speak", :user_id => 1 }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 1, :name => "Bluth Company" }, :organization_id => 1 }.to_json] }
81
+ stub.get("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke", :comments => [{ :comment => { :id => 2, :body => "Tobias, you blow hard!", :user_id => 1 } }, { :comment => { :id => 3, :body => "I wouldn't mind kissing that man between the cheeks, so to speak", :user_id => 1 } }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 1, :name => "Bluth Company" }, :organization_id => 1 }.to_json] }
82
82
  stub.get("/users/2") { |env| [200, {}, { :id => 2, :name => "Lindsay Fünke", :organization_id => 2 }.to_json] }
83
- stub.get("/users/1/comments") { |env| [200, {}, [{ :id => 4, :body => "They're having a FIRESALE?" }].to_json] }
84
- stub.get("/users/2/comments") { |env| [200, {}, [{ :id => 4, :body => "They're having a FIRESALE?" }, { :id => 5, :body => "Is this the tiny town from Footloose?" }].to_json] }
83
+ stub.get("/users/1/comments") { |env| [200, {}, [{ :comment => { :id => 4, :body => "They're having a FIRESALE?" } }].to_json] }
84
+ stub.get("/users/2/comments") { |env| [200, {}, [{ :comment => { :id => 4, :body => "They're having a FIRESALE?" } }, { :comment => { :id => 5, :body => "Is this the tiny town from Footloose?" } }].to_json] }
85
85
  stub.get("/users/2/role") { |env| [200, {}, { :id => 2, :body => "User" }.to_json] }
86
86
  stub.get("/users/1/role") { |env| [200, {}, { :id => 3, :body => "User" }.to_json] }
87
87
  stub.get("/users/1/posts") { |env| [200, {}, {:id => 1, :body => 'blogging stuff', :admin_id => 1 }.to_json] }
88
- stub.get("/organizations/1") { |env| [200, {}, { :id => 1, :name => "Bluth Company Foo" }.to_json] }
89
- stub.post("/users") { |env| [200, {}, { :id => 5, :name => "Mr. Krabs", :comments => [{ :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
90
- stub.put("/users/5") { |env| [200, {}, { :id => 5, :name => "Clancy Brown", :comments => [{ :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
91
- stub.delete("/users/5") { |env| [200, {}, { :id => 5, :name => "Clancy Brown", :comments => [{ :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
88
+ stub.get("/organizations/1") { |env| [200, {}, { :organization => { :id => 1, :name => "Bluth Company Foo" } }.to_json] }
89
+ stub.post("/users") { |env| [200, {}, { :id => 5, :name => "Mr. Krabs", :comments => [{ :comment => { :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 } }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
90
+ stub.put("/users/5") { |env| [200, {}, { :id => 5, :name => "Clancy Brown", :comments => [{ :comment => { :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 } }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
91
+ stub.delete("/users/5") { |env| [200, {}, { :id => 5, :name => "Clancy Brown", :comments => [{ :comment => { :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 } }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
92
92
 
93
93
  stub.get("/organizations/2") do |env|
94
94
  if env[:params]["admin"] == "true"
95
- [200, {}, { :id => 2, :name => "Bluth Company (admin)" }.to_json]
95
+ [200, {}, { :organization => { :id => 2, :name => "Bluth Company (admin)" } }.to_json]
96
96
  else
97
- [200, {}, { :id => 2, :name => "Bluth Company" }.to_json]
97
+ [200, {}, { :organization => { :id => 2, :name => "Bluth Company" } }.to_json]
98
98
  end
99
99
  end
100
100
  end
@@ -108,12 +108,16 @@ describe Her::Model::Relationships do
108
108
  end
109
109
  spawn_model "Foo::Comment" do
110
110
  belongs_to :user
111
+ parse_root_in_json true
111
112
  end
112
113
  spawn_model "Foo::Post" do
113
114
  belongs_to :admin, :class_name => 'Foo::User'
114
115
  end
115
116
 
116
- spawn_model "Foo::Organization"
117
+ spawn_model "Foo::Organization" do
118
+ parse_root_in_json true
119
+ end
120
+
117
121
  spawn_model "Foo::Role"
118
122
 
119
123
  @user_with_included_data = Foo::User.find(1)
@@ -182,14 +186,14 @@ describe Her::Model::Relationships do
182
186
  @user_with_included_data.organization(:foo_id => 1).name.should == "Bluth Company Foo"
183
187
  end
184
188
 
185
- it "can tell if it has a relationship" do
186
- @user_without_included_data.has_relationship?(:unknown_relationship).should be_false
187
- @user_without_included_data.has_relationship?(:organization).should be_true
189
+ it "can tell if it has a association" do
190
+ @user_without_included_data.has_association?(:unknown_association).should be_false
191
+ @user_without_included_data.has_association?(:organization).should be_true
188
192
  end
189
193
 
190
- it "fetches the resource corresponding to a named relationship" do
191
- @user_without_included_data.get_relationship(:unknown_relationship).should be_nil
192
- @user_without_included_data.get_relationship(:organization).name.should == "Bluth Company"
194
+ it "fetches the resource corresponding to a named association" do
195
+ @user_without_included_data.get_association(:unknown_association).should be_nil
196
+ @user_without_included_data.get_association(:organization).name.should == "Bluth Company"
193
197
  end
194
198
 
195
199
  it "pass query string parameters when additional arguments are passed" do
@@ -216,21 +220,21 @@ describe Her::Model::Relationships do
216
220
  end
217
221
  end
218
222
 
219
- context "handling relationships with details" do
223
+ context "handling associations with details" do
220
224
  before do
221
225
  Her::API.setup :url => "https://api.example.com" do |builder|
222
226
  builder.use Her::Middleware::FirstLevelParseJSON
223
227
  builder.use Faraday::Request::UrlEncoded
224
228
  builder.adapter :test do |stub|
225
- stub.get("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke", :organization => { :id => 1, :name => "Bluth Company" }, :organization_id => 1 }.to_json] }
229
+ stub.get("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke", :organization => { :id => 1, :name => "Bluth Company Inc." }, :organization_id => 1 }.to_json] }
226
230
  stub.get("/users/2") { |env| [200, {}, { :id => 2, :name => "Lindsay Fünke", :organization_id => 1 }.to_json] }
227
- stub.get("/users/3") { |env| [200, {}, { :id => 2, :name => "Lindsay Fünke", :organization => nil }.to_json] }
231
+ stub.get("/users/3") { |env| [200, {}, { :id => 2, :name => "Lindsay Fünke", :company => nil }.to_json] }
228
232
  stub.get("/companies/1") { |env| [200, {}, { :id => 1, :name => "Bluth Company" }.to_json] }
229
233
  end
230
234
  end
231
235
 
232
236
  spawn_model "Foo::User" do
233
- belongs_to :company, :path => "/organizations/:id", :foreign_key => :organization_id
237
+ belongs_to :company, :path => "/organizations/:id", :foreign_key => :organization_id, :data_key => :organization
234
238
  end
235
239
 
236
240
  spawn_model "Foo::Company"
@@ -243,11 +247,11 @@ describe Her::Model::Relationships do
243
247
  it "maps an array of included data through belongs_to" do
244
248
  @user_with_included_data.company.should be_a(Foo::Company)
245
249
  @user_with_included_data.company.id.should == 1
246
- @user_with_included_data.company.name.should == "Bluth Company"
250
+ @user_with_included_data.company.name.should == "Bluth Company Inc."
247
251
  end
248
252
 
249
253
  it "does not map included data if it’s nil" do
250
- @user_with_included_nil_data.organization.should be_nil
254
+ @user_with_included_nil_data.company.should be_nil
251
255
  end
252
256
 
253
257
  it "fetches data that was not included through belongs_to" do
@@ -2,7 +2,7 @@
2
2
  require File.join(File.dirname(__FILE__), "../spec_helper.rb")
3
3
 
4
4
  describe Her::Model::NestedAttributes do
5
- context "with a belongs_to relation" do
5
+ context "with a belongs_to association" do
6
6
  before do
7
7
  Her::API.setup :url => "https://api.example.com" do |builder|
8
8
  builder.use Her::Middleware::FirstLevelParseJSON
@@ -35,7 +35,7 @@ describe Her::Model::NestedAttributes do
35
35
  end
36
36
  end
37
37
 
38
- context "with a has_one relation" do
38
+ context "with a has_one association" do
39
39
  before do
40
40
  Her::API.setup :url => "https://api.example.com" do |builder|
41
41
  builder.use Her::Middleware::FirstLevelParseJSON
@@ -68,7 +68,7 @@ describe Her::Model::NestedAttributes do
68
68
  end
69
69
  end
70
70
 
71
- context "with a has_many relation" do
71
+ context "with a has_many association" do
72
72
  before do
73
73
  Her::API.setup :url => "https://api.example.com" do |builder|
74
74
  builder.use Her::Middleware::FirstLevelParseJSON
@@ -145,7 +145,7 @@ describe Her::Model::ORM do
145
145
  builder.use Faraday::Request::UrlEncoded
146
146
  builder.adapter :test do |stub|
147
147
  stub.get("/users/1") { |env| [200, {}, { :id => 1, :friends => ["Maeby", "GOB", "Anne"] }.to_json] }
148
- stub.get("/users/2") { |env| [200, {}, { :id => 1, :organization => true }.to_json] }
148
+ stub.get("/users/2") { |env| [200, {}, { :id => 1 }.to_json] }
149
149
  end
150
150
  end
151
151
 
@@ -155,16 +155,11 @@ describe Her::Model::ORM do
155
155
 
156
156
  def friends=(val)
157
157
  val = val.gsub("\r", "").split("\n").map { |friend| friend.gsub(/^\s*\*\s*/, "") } if val and val.is_a?(String)
158
- @data[:friends] = val
158
+ @attributes[:friends] = val
159
159
  end
160
160
 
161
161
  def friends
162
- @data[:friends].map { |friend| "* #{friend}" }.join("\n")
163
- end
164
-
165
- # Why would anybody want to do this? I don’t know.
166
- def organization=(organization)
167
- @data[:organization] = { :foo => :bar }
162
+ @attributes[:friends].map { |friend| "* #{friend}" }.join("\n")
168
163
  end
169
164
  end
170
165
  end
@@ -173,21 +168,16 @@ describe Her::Model::ORM do
173
168
  @user = User.find(1)
174
169
  @user.friends.should == "* Maeby\n* GOB\n* Anne"
175
170
  @user.instance_eval do
176
- @data[:friends] = ["Maeby", "GOB", "Anne"]
171
+ @attributes[:friends] = ["Maeby", "GOB", "Anne"]
177
172
  end
178
173
  end
179
174
 
180
- it "handles custom setters with relationships" do
181
- @user = User.find(2)
182
- @user.organization.should == { :foo => :bar }
183
- end
184
-
185
175
  it "handles custom getters" do
186
176
  @user = User.new
187
177
  @user.friends = "* George\n* Oscar\n* Lucille"
188
178
  @user.friends.should == "* George\n* Oscar\n* Lucille"
189
179
  @user.instance_eval do
190
- @data[:friends] = ["George", "Oscar", "Lucille"]
180
+ @attributes[:friends] = ["George", "Oscar", "Lucille"]
191
181
  end
192
182
  end
193
183
  end
@@ -61,7 +61,7 @@ describe Her::Model::Paths do
61
61
 
62
62
  it "raises exceptions when building a path without required custom variables" do
63
63
  Foo::User.collection_path "/organizations/:organization_id/utilisateurs"
64
- expect { Foo::User.build_request_path(:id => "foo") }.to raise_error(Her::Errors::PathError)
64
+ expect { Foo::User.build_request_path(:id => "foo") }.to raise_error(Her::Errors::PathError, "Missing :_organization_id parameter to build the request path. Path is `/organizations/:organization_id/utilisateurs/:id`. Parameters are `{:id=>\"foo\"}`.")
65
65
  end
66
66
  end
67
67
  end
@@ -115,12 +115,12 @@ describe Her::Model::Paths do
115
115
 
116
116
  it "raises exceptions when building a path without required custom variables" do
117
117
  Foo::AdminUser.collection_path "/organizations/:organization_id/users"
118
- expect { Foo::AdminUser.build_request_path(:id => "foo") }.to raise_error(Her::Errors::PathError)
118
+ expect { Foo::AdminUser.build_request_path(:id => "foo") }.to raise_error(Her::Errors::PathError, "Missing :_organization_id parameter to build the request path. Path is `/organizations/:organization_id/users/:id`. Parameters are `{:id=>\"foo\"}`.")
119
119
  end
120
120
 
121
121
  it "raises exceptions when building a relative path without required custom variables" do
122
122
  Foo::AdminUser.collection_path "organizations/:organization_id/users"
123
- expect { Foo::AdminUser.build_request_path(:id => "foo") }.to raise_error(Her::Errors::PathError)
123
+ expect { Foo::AdminUser.build_request_path(:id => "foo") }.to raise_error(Her::Errors::PathError, "Missing :_organization_id parameter to build the request path. Path is `organizations/:organization_id/users/:id`. Parameters are `{:id=>\"foo\"}`.")
124
124
  end
125
125
  end
126
126
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: her
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rémi Prévost
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-03-10 00:00:00.000000000 Z
11
+ date: 2013-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -142,19 +142,20 @@ files:
142
142
  - lib/her/middleware/first_level_parse_json.rb
143
143
  - lib/her/middleware/second_level_parse_json.rb
144
144
  - lib/her/model.rb
145
+ - lib/her/model/associations.rb
145
146
  - lib/her/model/base.rb
146
147
  - lib/her/model/http.rb
147
148
  - lib/her/model/introspection.rb
148
149
  - lib/her/model/nested_attributes.rb
149
150
  - lib/her/model/orm.rb
150
151
  - lib/her/model/paths.rb
151
- - lib/her/model/relationships.rb
152
152
  - lib/her/version.rb
153
153
  - spec/api_spec.rb
154
154
  - spec/collection_spec.rb
155
155
  - spec/middleware/accept_json_spec.rb
156
156
  - spec/middleware/first_level_parse_json_spec.rb
157
157
  - spec/middleware/second_level_parse_json_spec.rb
158
+ - spec/model/associations_spec.rb
158
159
  - spec/model/callbacks_spec.rb
159
160
  - spec/model/dirty_spec.rb
160
161
  - spec/model/http_spec.rb
@@ -162,7 +163,6 @@ files:
162
163
  - spec/model/nested_attributes_spec.rb
163
164
  - spec/model/orm_spec.rb
164
165
  - spec/model/paths_spec.rb
165
- - spec/model/relationships_spec.rb
166
166
  - spec/model/validations_spec.rb
167
167
  - spec/model_spec.rb
168
168
  - spec/spec_helper.rb
@@ -197,6 +197,7 @@ test_files:
197
197
  - spec/middleware/accept_json_spec.rb
198
198
  - spec/middleware/first_level_parse_json_spec.rb
199
199
  - spec/middleware/second_level_parse_json_spec.rb
200
+ - spec/model/associations_spec.rb
200
201
  - spec/model/callbacks_spec.rb
201
202
  - spec/model/dirty_spec.rb
202
203
  - spec/model/http_spec.rb
@@ -204,7 +205,6 @@ test_files:
204
205
  - spec/model/nested_attributes_spec.rb
205
206
  - spec/model/orm_spec.rb
206
207
  - spec/model/paths_spec.rb
207
- - spec/model/relationships_spec.rb
208
208
  - spec/model/validations_spec.rb
209
209
  - spec/model_spec.rb
210
210
  - spec/spec_helper.rb