attribution 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Rakefile +1 -1
- data/attribution.gemspec +1 -1
- data/lib/attribution/version.rb +1 -1
- data/lib/attribution.rb +89 -13
- data/test/attribution_model_test.rb +1 -1
- data/test/attribution_test.rb +40 -4
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d198859156d76d0e0c11d018834a556df0dbdfcb
|
4
|
+
data.tar.gz: 0a103445301e0ea36e62bf12b6d2089b015b9496
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 053aeb28529a3da23866dfdf01f4ccc53d1c9d07517c9e2e22647acef67d73614800b69517f7984b39af2112235f5cda34caab72a3390b8958e7b65bad754629
|
7
|
+
data.tar.gz: 380264f5c4aaf9df41bc2030de3c281d914983d7482939bcd54b54a2195bf8158b79a3d76a693c97f6ce58ee0aa7c9a5ec7ff44bcecf88b38affac8a9dd6f0fe
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0.0-
|
1
|
+
2.0.0-p247
|
data/Rakefile
CHANGED
data/attribution.gemspec
CHANGED
data/lib/attribution/version.rb
CHANGED
data/lib/attribution.rb
CHANGED
@@ -16,6 +16,7 @@ module Attribution
|
|
16
16
|
self.attributes = attributes
|
17
17
|
end
|
18
18
|
|
19
|
+
# @return [Hash] the attributes of this instance and their values
|
19
20
|
def attributes(*associations)
|
20
21
|
self.class.attribute_names.inject({}) do |attrs, attr|
|
21
22
|
attrs[attr] = send(attr)
|
@@ -24,6 +25,7 @@ module Attribution
|
|
24
25
|
end
|
25
26
|
alias_method :to_h, :attributes
|
26
27
|
|
28
|
+
# @param [String, Hash] attributes The attributes and their values
|
27
29
|
def attributes=(attributes)
|
28
30
|
attributes = case attributes
|
29
31
|
when String then JSON.parse(attributes)
|
@@ -40,6 +42,10 @@ module Attribution
|
|
40
42
|
end
|
41
43
|
|
42
44
|
module ClassMethods
|
45
|
+
|
46
|
+
# @param [Hash, Attribution] obj The Hash or Object to convert to
|
47
|
+
# an instance of this class
|
48
|
+
# @return [Attribution] An instance of this class
|
43
49
|
def cast(obj)
|
44
50
|
case obj
|
45
51
|
when Hash then new(obj)
|
@@ -48,6 +54,8 @@ module Attribution
|
|
48
54
|
end
|
49
55
|
end
|
50
56
|
|
57
|
+
# @return [Hash{Symbol => Object}] Each attribute name, type and
|
58
|
+
# any related metadata in the order in which they were defined
|
51
59
|
def attributes
|
52
60
|
@attributes ||= if superclass && superclass.respond_to?(:attributes)
|
53
61
|
superclass.attributes.dup
|
@@ -56,16 +64,28 @@ module Attribution
|
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
67
|
+
# @return [Array<Symbol>] The names of the attributes
|
68
|
+
# in the order in which they were defined
|
59
69
|
def attribute_names
|
60
70
|
@attribute_names ||= attributes.map{|a| a[:name] }
|
61
71
|
end
|
62
72
|
|
73
|
+
# Attribute macros
|
74
|
+
|
75
|
+
# Defines an attribute
|
76
|
+
#
|
77
|
+
# @param [String] name The name of the attribute
|
78
|
+
# @param [Symbol] type The type of the attribute
|
79
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
63
80
|
def add_attribute(name, type, metadata={})
|
64
81
|
attr_reader name
|
65
82
|
attributes << (metadata || {}).merge(:name => name.to_sym, :type => type.to_sym)
|
66
83
|
end
|
67
84
|
|
68
|
-
#
|
85
|
+
# Defines a string attribute
|
86
|
+
#
|
87
|
+
# @param [Symbol] attr The name of the attribute
|
88
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
69
89
|
def string(attr, metadata={})
|
70
90
|
add_attribute(attr, :string, metadata)
|
71
91
|
define_method("#{attr}=") do |arg|
|
@@ -73,6 +93,10 @@ module Attribution
|
|
73
93
|
end
|
74
94
|
end
|
75
95
|
|
96
|
+
# Defines a boolean attribute
|
97
|
+
#
|
98
|
+
# @param [Symbol] attr The name of the attribute
|
99
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
76
100
|
def boolean(attr, metadata={})
|
77
101
|
add_attribute(attr, :boolean, metadata)
|
78
102
|
define_method("#{attr}=") do |arg|
|
@@ -87,6 +111,10 @@ module Attribution
|
|
87
111
|
alias_method "#{attr}?", attr
|
88
112
|
end
|
89
113
|
|
114
|
+
# Defines a integer attribute
|
115
|
+
#
|
116
|
+
# @param [Symbol] attr The name of the attribute
|
117
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
90
118
|
def integer(attr, metadata={})
|
91
119
|
add_attribute(attr, :integer, metadata)
|
92
120
|
define_method("#{attr}=") do |arg|
|
@@ -94,6 +122,10 @@ module Attribution
|
|
94
122
|
end
|
95
123
|
end
|
96
124
|
|
125
|
+
# Defines a float attribute
|
126
|
+
#
|
127
|
+
# @param [Symbol] attr The name of the attribute
|
128
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
97
129
|
def float(attr, metadata={})
|
98
130
|
add_attribute(attr, :float, metadata)
|
99
131
|
define_method("#{attr}=") do |arg|
|
@@ -101,6 +133,10 @@ module Attribution
|
|
101
133
|
end
|
102
134
|
end
|
103
135
|
|
136
|
+
# Defines a decimal attribute
|
137
|
+
#
|
138
|
+
# @param [Symbol] attr The name of the attribute
|
139
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
104
140
|
def decimal(attr, metadata={})
|
105
141
|
add_attribute(attr, :decimal, metadata)
|
106
142
|
define_method("#{attr}=") do |arg|
|
@@ -108,6 +144,10 @@ module Attribution
|
|
108
144
|
end
|
109
145
|
end
|
110
146
|
|
147
|
+
# Defines a date attribute
|
148
|
+
#
|
149
|
+
# @param [Symbol] attr The name of the attribute
|
150
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
111
151
|
def date(attr, metadata={})
|
112
152
|
add_attribute(attr, :date, metadata)
|
113
153
|
define_method("#{attr}=") do |arg|
|
@@ -125,6 +165,10 @@ module Attribution
|
|
125
165
|
end
|
126
166
|
end
|
127
167
|
|
168
|
+
# Defines a time attribute
|
169
|
+
#
|
170
|
+
# @param [Symbol] attr The name of the attribute
|
171
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
128
172
|
def time(attr, metadata={})
|
129
173
|
add_attribute(attr, :time, metadata)
|
130
174
|
define_method("#{attr}=") do |arg|
|
@@ -142,6 +186,10 @@ module Attribution
|
|
142
186
|
end
|
143
187
|
end
|
144
188
|
|
189
|
+
# Defines a time zone attribute, based on ActiveSupport::TimeZone
|
190
|
+
#
|
191
|
+
# @param [Symbol] attr The name of the attribute
|
192
|
+
# @param [Hash{Symbol => Object}] metadata The metadata for the attribute
|
145
193
|
def time_zone(attr, metadata={})
|
146
194
|
add_attribute(attr, :time_zone, metadata)
|
147
195
|
define_method("#{attr}=") do |arg|
|
@@ -150,10 +198,20 @@ module Attribution
|
|
150
198
|
end
|
151
199
|
|
152
200
|
# Association macros
|
201
|
+
|
202
|
+
# Defines an attribute that is a reference to another Attribution class.
|
203
|
+
#
|
204
|
+
# @param [Symbol] association_name The name of the association
|
205
|
+
# @param [Hash] metadata Extra information about the association.
|
206
|
+
# @option metadata [String] :class_name Class of the association,
|
207
|
+
# defaults to a class name based on the association name
|
153
208
|
def belongs_to(association_name, metadata={})
|
154
209
|
# foo_id
|
155
210
|
id_getter = "#{association_name}_id".to_sym
|
156
211
|
add_attribute(id_getter, :integer, metadata)
|
212
|
+
|
213
|
+
association_class_name = metadata.try(:fetch, :class_name, [name.deconstantize, association_name.to_s.classify].reject(&:blank?).join('::'))
|
214
|
+
|
157
215
|
define_method(id_getter) do
|
158
216
|
ivar = "@#{id_getter}"
|
159
217
|
if instance_variable_defined?(ivar)
|
@@ -177,11 +235,12 @@ module Attribution
|
|
177
235
|
if instance_variable_defined?("@#{association_name}")
|
178
236
|
instance_variable_get("@#{association_name}")
|
179
237
|
elsif id = instance_variable_get("@#{association_name}_id")
|
238
|
+
|
180
239
|
# TODO: Support a more generic version of lazy-loading
|
181
240
|
begin
|
182
|
-
association_class =
|
241
|
+
association_class = Object.const_get(association_class_name)
|
183
242
|
rescue NameError => ex
|
184
|
-
raise ArgumentError.new("Association #{association_name} in #{self.class} is invalid because #{
|
243
|
+
raise ArgumentError.new("Association #{association_name} in #{self.class} is invalid because #{association_class_name} does not exist")
|
185
244
|
end
|
186
245
|
|
187
246
|
if association_class.respond_to?(:find)
|
@@ -195,9 +254,9 @@ module Attribution
|
|
195
254
|
# foo=
|
196
255
|
define_method("#{association_name}=") do |arg|
|
197
256
|
begin
|
198
|
-
association_class =
|
257
|
+
association_class = Object.const_get(association_class_name)
|
199
258
|
rescue NameError => ex
|
200
|
-
raise ArgumentError.new("Association #{association_name} in #{self.class} is invalid because #{
|
259
|
+
raise ArgumentError.new("Association #{association_name} in #{self.class} is invalid because #{association_class_name} does not exist")
|
201
260
|
end
|
202
261
|
|
203
262
|
if instance_variable_defined?("@#{association_name}_id")
|
@@ -207,15 +266,24 @@ module Attribution
|
|
207
266
|
end
|
208
267
|
end
|
209
268
|
|
210
|
-
|
269
|
+
# Defines an attribute that is a reference to an Array of another Attribution class.
|
270
|
+
#
|
271
|
+
# @param [Symbol] association_name The name of the association
|
272
|
+
# @param [Hash] metadata Extra information about the association.
|
273
|
+
# @option metadata [String] :class_name Class of the association,
|
274
|
+
# defaults to a class name based on the association name
|
275
|
+
def has_many(association_name, metadata={})
|
276
|
+
|
277
|
+
association_class_name = metadata.try(:fetch, :class_name, [name.deconstantize, association_name.to_s.singularize.classify].reject(&:blank?).join('::'))
|
278
|
+
|
211
279
|
# foos
|
212
280
|
define_method(association_name) do |*query|
|
213
281
|
|
214
282
|
# TODO: Support a more generic version of lazy-loading
|
215
283
|
begin
|
216
|
-
association_class =
|
284
|
+
association_class = Object.const_get(association_class_name)
|
217
285
|
rescue NameError => ex
|
218
|
-
raise ArgumentError.new("Association #{association_name} in #{self.class} is invalid because #{
|
286
|
+
raise ArgumentError.new("Association #{association_name} in #{self.class} is invalid because #{association_class_name} does not exist")
|
219
287
|
end
|
220
288
|
|
221
289
|
if query.empty? # Ex: Books.all, so we want to cache it.
|
@@ -227,7 +295,7 @@ module Attribution
|
|
227
295
|
end
|
228
296
|
else # Ex: Book.all(:name => "The..."), so we do not want to cache it
|
229
297
|
if association_class.respond_to?(:all)
|
230
|
-
Array(association_class.all({"#{self.class.name.underscore}_id" => id}.merge(query.first)))
|
298
|
+
Array(association_class.all({"#{self.class.name.demodulize.underscore}_id" => id}.merge(query.first)))
|
231
299
|
end
|
232
300
|
end
|
233
301
|
end
|
@@ -236,15 +304,23 @@ module Attribution
|
|
236
304
|
define_method("#{association_name}=") do |arg|
|
237
305
|
# TODO: put this in method
|
238
306
|
begin
|
239
|
-
association_class =
|
307
|
+
association_class = Object.const_get(association_class_name)
|
240
308
|
rescue NameError => ex
|
241
|
-
raise ArgumentError.new("Association #{association_name} in #{self.class} is invalid because #{
|
309
|
+
raise ArgumentError.new("Association #{association_name} in #{self.class} is invalid because #{association_class_name} does not exist")
|
242
310
|
end
|
243
311
|
|
312
|
+
attr_name = self.class.name.demodulize.underscore
|
244
313
|
objs = (arg.is_a?(Hash) ? arg.values : Array(arg)).map do |obj|
|
245
314
|
o = association_class.cast(obj)
|
246
|
-
|
247
|
-
o.
|
315
|
+
|
316
|
+
if o.respond_to?("#{attr_name}=")
|
317
|
+
o.send("#{attr_name}=", self)
|
318
|
+
end
|
319
|
+
|
320
|
+
if o.respond_to?("#{attr_name}_id=") && respond_to?(:id)
|
321
|
+
o.send("#{attr_name}_id=", id)
|
322
|
+
end
|
323
|
+
|
248
324
|
o
|
249
325
|
end
|
250
326
|
instance_variable_set("@#{association_name}", objs)
|
@@ -4,7 +4,7 @@ require 'attribution/model'
|
|
4
4
|
class Article
|
5
5
|
include Attribution::Model
|
6
6
|
|
7
|
-
string :title, required: true, format: { with:
|
7
|
+
string :title, required: true, format: { with: /\A\w/, message: "must start with a letter" }, length: 4..20
|
8
8
|
end
|
9
9
|
|
10
10
|
class AttributionModelTest < Test::Unit::TestCase
|
data/test/attribution_test.rb
CHANGED
@@ -11,10 +11,10 @@ class Address
|
|
11
11
|
string :state
|
12
12
|
string :zip
|
13
13
|
|
14
|
-
belongs_to :author
|
14
|
+
belongs_to :author, :class_name => 'Person'
|
15
15
|
end
|
16
16
|
|
17
|
-
class
|
17
|
+
class Person
|
18
18
|
include Attribution
|
19
19
|
|
20
20
|
integer :id
|
@@ -94,6 +94,32 @@ class Grandchild < Child
|
|
94
94
|
string :baz
|
95
95
|
end
|
96
96
|
|
97
|
+
module Music
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
module Music
|
102
|
+
class Album
|
103
|
+
include Attribution
|
104
|
+
|
105
|
+
has_many :tracks
|
106
|
+
|
107
|
+
string :artist
|
108
|
+
string :title
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
module Music
|
113
|
+
class Track
|
114
|
+
include Attribution
|
115
|
+
|
116
|
+
belongs_to :album
|
117
|
+
|
118
|
+
integer :number
|
119
|
+
string :title
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
97
123
|
class AttributionTest < Test::Unit::TestCase
|
98
124
|
|
99
125
|
def test_create
|
@@ -254,11 +280,21 @@ class AttributionTest < Test::Unit::TestCase
|
|
254
280
|
end
|
255
281
|
|
256
282
|
def test_has_many_association_name
|
257
|
-
|
258
|
-
assert_equal [1],
|
283
|
+
person = Person.new(addresses: [{id: 1}])
|
284
|
+
assert_equal [1], person.addresses.map(&:id)
|
259
285
|
end
|
260
286
|
|
261
287
|
def test_attribute_inheritence
|
262
288
|
assert_equal [:foo, :bar, :baz], Grandchild.attribute_names
|
263
289
|
end
|
290
|
+
|
291
|
+
def test_namespaced_belongs_to
|
292
|
+
track = Music::Track.new(number: 1, title: "Elevator Music", album: { artist: "Beck", title: "The Information" })
|
293
|
+
assert_equal "Beck", track.album.artist
|
294
|
+
end
|
295
|
+
|
296
|
+
def test_namespaced_has_many
|
297
|
+
album = Music::Album.new(artist: "Beck", title: "The Information", tracks: [ { number: 1, title: "Elevator Music" } ])
|
298
|
+
assert_equal "Elevator Music", album.tracks.first.title
|
299
|
+
end
|
264
300
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attribution
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Barry
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -95,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
95
|
version: '0'
|
96
96
|
requirements: []
|
97
97
|
rubyforge_project:
|
98
|
-
rubygems_version: 2.0.
|
98
|
+
rubygems_version: 2.0.3
|
99
99
|
signing_key:
|
100
100
|
specification_version: 4
|
101
101
|
summary: Add attributes to Ruby objects
|
@@ -103,3 +103,4 @@ test_files:
|
|
103
103
|
- test/attribution_model_test.rb
|
104
104
|
- test/attribution_test.rb
|
105
105
|
- test/test_helper.rb
|
106
|
+
has_rdoc:
|