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 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: