attribution 0.4.0 → 0.5.0
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.
- data/README.md +114 -61
- data/attribution.gemspec +2 -1
- data/lib/attribution/id.rb +20 -0
- data/lib/attribution/model.rb +16 -0
- data/lib/attribution/timestamps.rb +10 -0
- data/lib/attribution/validations.rb +53 -0
- data/lib/attribution/version.rb +1 -1
- data/lib/attribution.rb +4 -4
- data/test/attribution_model_test.rb +16 -0
- data/test/attribution_test.rb +2 -3
- data/test/test_helper.rb +2 -0
- metadata +28 -3
data/README.md
CHANGED
@@ -20,66 +20,70 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
You can define attributes like this:
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
23
|
+
``` ruby
|
24
|
+
class Book
|
25
|
+
include Attribution
|
26
|
+
|
27
|
+
integer :id
|
28
|
+
string :title
|
29
|
+
decimal :price
|
30
|
+
date :published_on
|
31
|
+
boolean :ebook_available
|
32
|
+
boolean :used
|
33
|
+
float :shipping_weight
|
34
|
+
time :created_at
|
35
|
+
time :updated_at
|
36
|
+
time_zone :time_zone
|
37
|
+
|
38
|
+
has_many :chapters
|
39
|
+
end
|
40
|
+
|
41
|
+
class Chapter
|
42
|
+
include Attribution
|
43
|
+
|
44
|
+
integer :number
|
45
|
+
string :title
|
46
|
+
integer :page_number
|
47
|
+
|
48
|
+
belongs_to :book
|
49
|
+
end
|
50
|
+
```
|
49
51
|
|
50
52
|
And then you can pass in a Hash or a String of JSON to initialize the object:
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
54
|
+
``` ruby
|
55
|
+
json = %{{
|
56
|
+
"id": 1,
|
57
|
+
"title": "Rework",
|
58
|
+
"price": "22.00",
|
59
|
+
"published_on": "March 9, 2010",
|
60
|
+
"ebook_available": "yes",
|
61
|
+
"used": "no",
|
62
|
+
"shipping_weight": "14.4",
|
63
|
+
"created_at": "2013-02-20 05:39:45 -0500",
|
64
|
+
"updated_at": "2013-02-20T05:40:37-05:00",
|
65
|
+
"time_zone": "Eastern Time (US & Canada)",
|
66
|
+
"chapters": [
|
67
|
+
{
|
68
|
+
"number": "1",
|
69
|
+
"title": "Introduction",
|
70
|
+
"page_number": "1"
|
71
|
+
},
|
72
|
+
{
|
73
|
+
"number": "2",
|
74
|
+
"title": "Takedowns",
|
75
|
+
"page_number": "7"
|
76
|
+
},
|
77
|
+
{
|
78
|
+
"number": "3",
|
79
|
+
"title": "Go",
|
80
|
+
"page_number": "29"
|
81
|
+
}
|
82
|
+
]
|
83
|
+
}}
|
84
|
+
|
85
|
+
book = Book.new(json)
|
86
|
+
```
|
83
87
|
|
84
88
|
The object is populated based on the data, the values are converted into the type defined by the attribute:
|
85
89
|
|
@@ -132,17 +136,65 @@ You can access the values of all attributes as a hash:
|
|
132
136
|
|
133
137
|
You can also add any arbitrary metadata to any attribute:
|
134
138
|
|
135
|
-
|
136
|
-
|
139
|
+
``` ruby
|
140
|
+
class Book
|
141
|
+
include Attribution
|
137
142
|
|
138
|
-
|
139
|
-
|
143
|
+
decimal :price, :required => true, :doc => "Price in USD", :whatever => "why not?"
|
144
|
+
end
|
145
|
+
```
|
140
146
|
|
141
147
|
And retrieve that metadata any time:
|
142
148
|
|
143
149
|
>> Book.attributes
|
144
150
|
=> [{:required=>true, :doc=>"Price in USD", :whatever=>"why not?", :name=>:price, :type=>:decimal}]
|
145
151
|
|
152
|
+
Attribution also has a module to make any object act more like a model:
|
153
|
+
|
154
|
+
``` ruby
|
155
|
+
class Book
|
156
|
+
include Attribution::Model
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
By using `Attribution::Model`, your object will:
|
161
|
+
|
162
|
+
* Have an id that is an integer
|
163
|
+
* Implementation for equality and hash based on the id
|
164
|
+
* Have a created_at that is a time
|
165
|
+
* Have an updated_at that is a time
|
166
|
+
* Include [ActiveModel::Validations][am]
|
167
|
+
|
168
|
+
You can define validations in the standard way you do when using `ActiveModel::Validations`:
|
169
|
+
|
170
|
+
``` ruby
|
171
|
+
class Book
|
172
|
+
include Attribution::Model
|
173
|
+
|
174
|
+
belongs_to :author
|
175
|
+
|
176
|
+
string :title
|
177
|
+
|
178
|
+
validates :title, :presence => true
|
179
|
+
validates :title, :uniqueness => true
|
180
|
+
validates :title, :format => { :with => /^\w/, :message => "must start with a letter" }
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
Or, more concisely, you can define the validation as part of the attribute definition:
|
185
|
+
|
186
|
+
``` ruby
|
187
|
+
class Book
|
188
|
+
include Attribution::Model
|
189
|
+
|
190
|
+
belongs_to :author
|
191
|
+
|
192
|
+
string :title, :required => true,
|
193
|
+
:unique => true,
|
194
|
+
:format => { :with => /^w/, :message => "must start with a letter" }
|
195
|
+
end
|
196
|
+
```
|
197
|
+
|
146
198
|
## Contributing
|
147
199
|
|
148
200
|
1. Fork it
|
@@ -152,3 +204,4 @@ And retrieve that metadata any time:
|
|
152
204
|
5. Create new Pull Request
|
153
205
|
|
154
206
|
[ar]: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
|
207
|
+
[am]: http://rubydoc.info/gems/activemodel
|
data/attribution.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = "attribution"
|
5
|
-
gem.version = "0.
|
5
|
+
gem.version = "0.5.0"
|
6
6
|
gem.authors = ["Paul Barry"]
|
7
7
|
gem.email = ["mail@paulbarry.com"]
|
8
8
|
gem.description = %q{Add attributes to Ruby objects}
|
@@ -16,4 +16,5 @@ Gem::Specification.new do |gem|
|
|
16
16
|
|
17
17
|
gem.add_runtime_dependency "activesupport"
|
18
18
|
gem.add_runtime_dependency "tzinfo"
|
19
|
+
gem.add_development_dependency "activemodel"
|
19
20
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Attribution
|
2
|
+
module ID
|
3
|
+
def self.included(cls)
|
4
|
+
cls.class_eval do
|
5
|
+
integer :id
|
6
|
+
|
7
|
+
alias_method :to_param, :id
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(o)
|
12
|
+
o.class == self.class && o.id == id
|
13
|
+
end
|
14
|
+
alias_method :eql?, :==
|
15
|
+
|
16
|
+
def hash
|
17
|
+
id.hash
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'attribution/id'
|
2
|
+
require 'attribution/timestamps'
|
3
|
+
require 'attribution/validations'
|
4
|
+
|
5
|
+
module Attribution
|
6
|
+
module Model
|
7
|
+
def self.included(cls)
|
8
|
+
cls.class_eval do
|
9
|
+
include Attribution
|
10
|
+
include ID
|
11
|
+
include Timestamps
|
12
|
+
include Validations
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module Attribution
|
4
|
+
module Validations
|
5
|
+
|
6
|
+
def self.included(cls)
|
7
|
+
cls.class_eval do
|
8
|
+
extend ClassMethods
|
9
|
+
include ActiveModel::Validations
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
VALIDATIONS = [
|
16
|
+
[:presence, :required],
|
17
|
+
[:presence],
|
18
|
+
[:uniqueness, :unique],
|
19
|
+
[:uniqueness],
|
20
|
+
[:format],
|
21
|
+
[:length],
|
22
|
+
[:inclusion],
|
23
|
+
[:numericality, :number],
|
24
|
+
[:numericality]
|
25
|
+
]
|
26
|
+
|
27
|
+
def add_attribute(name, type, metadata={})
|
28
|
+
super
|
29
|
+
VALIDATIONS.each do |validation_name, validation_alias|
|
30
|
+
validation_alias ||= validation_name
|
31
|
+
if metadata[validation_alias] == true
|
32
|
+
validates name, validation_name => true
|
33
|
+
elsif metadata[validation_alias]
|
34
|
+
validates name, validation_name => metadata[validation_alias]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def errors
|
42
|
+
@errors ||= ActiveModel::Errors.new(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
def errors=(errs)
|
46
|
+
if errs
|
47
|
+
errs.each do |attr, e|
|
48
|
+
errors.add attr, e
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/attribution/version.rb
CHANGED
data/lib/attribution.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'attribution/util'
|
3
|
+
require 'attribution/version'
|
4
4
|
|
5
5
|
module Attribution
|
6
6
|
BOOLEAN_TRUE_STRINGS = ['y','yes','t','true']
|
@@ -13,13 +13,13 @@ module Attribution
|
|
13
13
|
self.attributes = attributes
|
14
14
|
end
|
15
15
|
|
16
|
-
# TODO: Use associations argument as a way to specify which associations should be included
|
17
16
|
def attributes(*associations)
|
18
17
|
self.class.attribute_names.inject({}) do |attrs, attr|
|
19
18
|
attrs[attr] = send(attr)
|
20
19
|
attrs
|
21
20
|
end
|
22
21
|
end
|
22
|
+
alias_method :to_h, :attributes
|
23
23
|
|
24
24
|
def attributes=(attributes)
|
25
25
|
if attributes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'attribution/model'
|
3
|
+
|
4
|
+
class Article
|
5
|
+
include Attribution::Model
|
6
|
+
|
7
|
+
string :title, required: true, format: { with: /^\w/, message: "must start with a letter" }, length: 4..20
|
8
|
+
end
|
9
|
+
|
10
|
+
class AttributionModelTest < Test::Unit::TestCase
|
11
|
+
def test_model
|
12
|
+
article = Article.new(id: 1, created_at: Time.now, updated_at: Time.now)
|
13
|
+
assert !article.valid?
|
14
|
+
assert_equal ["can't be blank", "must start with a letter", "is too short (minimum is 4 characters)"], article.errors[:title]
|
15
|
+
end
|
16
|
+
end
|
data/test/attribution_test.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'attribution'
|
1
|
+
require 'test_helper'
|
3
2
|
|
4
3
|
#TODO: support using a different class name than the association name
|
5
4
|
class Author
|
@@ -128,7 +127,7 @@ class AttributionTest < Test::Unit::TestCase
|
|
128
127
|
{ :name => :page_number, :type => :integer },
|
129
128
|
{ :name => :book_id, :type => :integer }
|
130
129
|
], Chapter.attributes
|
131
|
-
assert_equal({ :id => nil, :number => 1, :title => nil, :page_number => nil, :book_id => nil }, chapter.
|
130
|
+
assert_equal({ :id => nil, :number => 1, :title => nil, :page_number => nil, :book_id => nil }, chapter.to_h)
|
132
131
|
end
|
133
132
|
|
134
133
|
def test_date_hash
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attribution
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.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: 2013-
|
12
|
+
date: 2013-04-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activemodel
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
description: Add attributes to Ruby objects
|
47
63
|
email:
|
48
64
|
- mail@paulbarry.com
|
@@ -57,9 +73,15 @@ files:
|
|
57
73
|
- Rakefile
|
58
74
|
- attribution.gemspec
|
59
75
|
- lib/attribution.rb
|
76
|
+
- lib/attribution/id.rb
|
77
|
+
- lib/attribution/model.rb
|
78
|
+
- lib/attribution/timestamps.rb
|
60
79
|
- lib/attribution/util.rb
|
80
|
+
- lib/attribution/validations.rb
|
61
81
|
- lib/attribution/version.rb
|
82
|
+
- test/attribution_model_test.rb
|
62
83
|
- test/attribution_test.rb
|
84
|
+
- test/test_helper.rb
|
63
85
|
homepage: http://github.com/pjb3/attribution
|
64
86
|
licenses: []
|
65
87
|
post_install_message:
|
@@ -80,9 +102,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
102
|
version: '0'
|
81
103
|
requirements: []
|
82
104
|
rubyforge_project:
|
83
|
-
rubygems_version: 1.8.
|
105
|
+
rubygems_version: 1.8.24
|
84
106
|
signing_key:
|
85
107
|
specification_version: 3
|
86
108
|
summary: Add attributes to Ruby objects
|
87
109
|
test_files:
|
110
|
+
- test/attribution_model_test.rb
|
88
111
|
- test/attribution_test.rb
|
112
|
+
- test/test_helper.rb
|
113
|
+
has_rdoc:
|