attribution 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
- class Book
24
- include Attribution
25
-
26
- integer :id
27
- string :title
28
- decimal :price
29
- date :published_on
30
- boolean :ebook_available
31
- boolean :used
32
- float :shipping_weight
33
- time :created_at
34
- time :updated_at
35
- time_zone :time_zone
36
-
37
- has_many :chapters
38
- end
39
-
40
- class Chapter
41
- include Attribution
42
-
43
- integer :number
44
- string :title
45
- integer :page_number
46
-
47
- belongs_to :book
48
- end
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
- json = %{{
53
- "id": 1,
54
- "title": "Rework",
55
- "price": "22.00",
56
- "published_on": "March 9, 2010",
57
- "ebook_available": "yes",
58
- "used": "no",
59
- "shipping_weight": "14.4",
60
- "created_at": "2013-02-20 05:39:45 -0500",
61
- "updated_at": "2013-02-20T05:40:37-05:00",
62
- "time_zone": "Eastern Time (US & Canada)",
63
- "chapters": [
64
- {
65
- "number": "1",
66
- "title": "Introduction",
67
- "page_number": "1"
68
- },
69
- {
70
- "number": "2",
71
- "title": "Takedowns",
72
- "page_number": "7"
73
- },
74
- {
75
- "number": "3",
76
- "title": "Go",
77
- "page_number": "29"
78
- }
79
- ]
80
- }}
81
-
82
- book = Book.new(json)
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
- class Book
136
- include Attribution
139
+ ``` ruby
140
+ class Book
141
+ include Attribution
137
142
 
138
- decimal :price, :required => true, :doc => "Price in USD", :whatever => "why not?"
139
- end
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.4.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,10 @@
1
+ module Attribution
2
+ module Timestamps
3
+ def self.included(cls)
4
+ cls.class_eval do
5
+ time :created_at
6
+ time :updated_at
7
+ end
8
+ end
9
+ end
10
+ 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
@@ -1,3 +1,3 @@
1
1
  module Attribution
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/attribution.rb CHANGED
@@ -1,6 +1,6 @@
1
- require "attribution/util"
2
- require "attribution/version"
3
- require "active_support/core_ext"
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
@@ -1,5 +1,4 @@
1
- require 'test/unit'
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.attributes)
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
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require 'attribution'
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.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-03-08 00:00:00.000000000 Z
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.25
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: