attribute_delegator 0.0.1
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/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.markdown +51 -0
- data/Rakefile +10 -0
- data/attribute_delegator.gemspec +24 -0
- data/lib/attribute_delegator.rb +51 -0
- data/lib/attribute_delegator/version.rb +3 -0
- data/test/attribute_delegator_test.rb +49 -0
- data/test/multiple_attribute_delegator_test.rb +40 -0
- data/test/setup.rb +28 -0
- metadata +124 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Attribute Delegator
|
2
|
+
|
3
|
+
AttributeDelegator is a gem that provides a class method to ActiveRecord
|
4
|
+
models which will generate native getter/setter methods for a the attributes of
|
5
|
+
a has_one delegate.
|
6
|
+
|
7
|
+
Sound complicated? It's not.
|
8
|
+
|
9
|
+
## How To Use
|
10
|
+
|
11
|
+
This is how to setup AttributeDelegator
|
12
|
+
|
13
|
+
# Contains a 'title' field.
|
14
|
+
class Entry < ActiveRecord::Base
|
15
|
+
include ::AttributeDelegator
|
16
|
+
has_one :entry_metadata
|
17
|
+
delegates_attributes_to :entry_metadata, [:page_views]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Contains 'entry_id' and 'page_views' fields.
|
21
|
+
class EntryMetadata < ActiveRecord::Base
|
22
|
+
belongs_to :entry
|
23
|
+
validates_uniqueness_of :entry_id
|
24
|
+
end
|
25
|
+
|
26
|
+
And this is how you can use it
|
27
|
+
|
28
|
+
# You can use normal getter/setter methods
|
29
|
+
e1 = Entry.new(:title => 'entry title')
|
30
|
+
e1.page_views = 50
|
31
|
+
e1.save!
|
32
|
+
assert_equal e1.page_views, e1.entry_metadata.page_views
|
33
|
+
|
34
|
+
# You can also set the attributes upon creation
|
35
|
+
e2 = Entry.create!(:title => 'Another title', :page_views => 50)
|
36
|
+
assert_equal 50, e2.page_views
|
37
|
+
|
38
|
+
# Finally, you can use attributes=, like you would submitting a form
|
39
|
+
e3 = Entry.new
|
40
|
+
e3.attributes = { :title => 'a title', :page_views => 50}
|
41
|
+
assert_equal 50, e3.page_views
|
42
|
+
|
43
|
+
## Why?
|
44
|
+
|
45
|
+
This gem was created to prevent large, STI models from bloating unecceesarily
|
46
|
+
when new fields needed to be added for certain subtypes, but not the
|
47
|
+
base class. This interface is particularly useful when the attributes
|
48
|
+
for that model are set by a form, because it means that the foreign
|
49
|
+
attributes can be seamlessly set using attributes=, and the form can
|
50
|
+
remain simple, even for attributes specific to one subtype.
|
51
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "attribute_delegator/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "attribute_delegator"
|
7
|
+
s.version = AttributeDelegator::VERSION
|
8
|
+
s.authors = ["Clif Reeder"]
|
9
|
+
s.email = ["clif@voxmedia.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{ActiveRecord extension that allows you to treat fields from another model/table as local attributes.}
|
12
|
+
s.description = %q{AttributeDelegator provides a class method to ActiveRecord models that dynamically generates getter/setter to treat the attributes of a has_one model like native attributes. This is particularly useful because it allows the delegated attributes to be assigned via model.attributes= {}, such as by a form submission.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "attribute_delegator"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency "activerecord", ">= 2.3.8"
|
22
|
+
s.add_dependency "activesupport", ">= 2.3.8"
|
23
|
+
s.add_development_dependency "sqlite3"
|
24
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "attribute_delegator/version"
|
2
|
+
|
3
|
+
module AttributeDelegator
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def delegates_attributes_to(the_delegate, attrs)
|
11
|
+
|
12
|
+
exists_method = :"ensure_#{the_delegate}_exists"
|
13
|
+
define_method exists_method do
|
14
|
+
build_method = "build_#{the_delegate.to_s}"
|
15
|
+
self.send(build_method.to_sym)
|
16
|
+
end
|
17
|
+
|
18
|
+
saved_method = :"ensure_#{the_delegate}_saved"
|
19
|
+
define_method saved_method do
|
20
|
+
delegate_obj = self.send(the_delegate)
|
21
|
+
return unless delegate_obj
|
22
|
+
if delegate_obj.changed? || delegate_obj.new_record?
|
23
|
+
delegate_obj.save!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# This would normally be an 'after_update' callback, but meta it cause the callback name changes
|
28
|
+
self.send(:after_update, saved_method)
|
29
|
+
|
30
|
+
attrs.each do |attr|
|
31
|
+
# Define the getter
|
32
|
+
define_method :"#{attr}" do
|
33
|
+
delegate_obj = self.send(the_delegate)
|
34
|
+
# Only send the attribute query if the object already
|
35
|
+
# exists. If it hasn't been instantiated, just return nil
|
36
|
+
if delegate_obj
|
37
|
+
delegate_obj.send(attr)
|
38
|
+
else
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#Define the setter
|
44
|
+
define_method :"#{attr}=" do |arg|
|
45
|
+
self.send(exists_method)
|
46
|
+
self.send(the_delegate).send("#{attr}=".to_sym, arg)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test/setup'
|
2
|
+
|
3
|
+
class Entry < ActiveRecord::Base
|
4
|
+
include ::AttributeDelegator
|
5
|
+
has_one :entry_metadata
|
6
|
+
delegates_attributes_to :entry_metadata, [:page_views]
|
7
|
+
end
|
8
|
+
|
9
|
+
class EntryMetadata < ActiveRecord::Base
|
10
|
+
belongs_to :entry
|
11
|
+
validates_uniqueness_of :entry_id
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
class TestAttributeDelegator < Test::Unit::TestCase
|
16
|
+
def setup
|
17
|
+
@entry = Entry.create!(:title => "Entry Title", :body => "Body of entry")
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_delegated_attributes_getters_and_setters
|
21
|
+
assert_nil @entry.page_views
|
22
|
+
page_views = 5
|
23
|
+
@entry.page_views = page_views
|
24
|
+
assert_equal @entry.page_views, page_views
|
25
|
+
assert @entry.entry_metadata.changed?
|
26
|
+
|
27
|
+
@entry.save!
|
28
|
+
@entry = Entry.find(@entry.id)
|
29
|
+
assert_equal @entry.page_views, @entry.entry_metadata.page_views
|
30
|
+
assert_equal false, @entry.entry_metadata.changed?, "if the parent object is saved, the delgate should be as well"
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_delegates_attributes_can_be_set_by_attributes=
|
34
|
+
assert_nil @entry.page_views
|
35
|
+
page_views = 5
|
36
|
+
@entry.attributes = { :page_views => page_views }
|
37
|
+
@entry.save!
|
38
|
+
|
39
|
+
entry = Entry.find(@entry.id)
|
40
|
+
assert_equal 5, entry.page_views
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_repeated_assignment_doesnt_break
|
44
|
+
@entry.page_views = 5
|
45
|
+
assert_equal 5, @entry.page_views
|
46
|
+
@entry.page_views = 10
|
47
|
+
assert_equal 10, @entry.page_views
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test/setup'
|
2
|
+
|
3
|
+
class Entry < ActiveRecord::Base
|
4
|
+
include ::AttributeDelegator
|
5
|
+
has_one :entry_metadata
|
6
|
+
delegates_attributes_to :entry_metadata, [:page_views]
|
7
|
+
|
8
|
+
has_one :entry_photo
|
9
|
+
delegates_attributes_to :entry_photo, [:photo]
|
10
|
+
end
|
11
|
+
|
12
|
+
class EntryMetadata < ActiveRecord::Base
|
13
|
+
belongs_to :entry
|
14
|
+
validates_uniqueness_of :entry_id
|
15
|
+
end
|
16
|
+
|
17
|
+
class EntryPhoto < ActiveRecord::Base
|
18
|
+
belongs_to :entry
|
19
|
+
validates_uniqueness_of :entry_id
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
class TestMultipleAttributeDelegators < Test::Unit::TestCase
|
24
|
+
def setup
|
25
|
+
@entry = Entry.create!(:title => "Entry Title", :body => "Body of entry")
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_working_with_multiple_delegates
|
29
|
+
page_views = 10
|
30
|
+
photo = "ok pretend this string is a photo"
|
31
|
+
e = Entry.create!({
|
32
|
+
:page_views => page_views,
|
33
|
+
:photo => photo
|
34
|
+
})
|
35
|
+
assert_equal photo, e.photo
|
36
|
+
assert_equal photo, e.entry_photo.photo
|
37
|
+
assert_equal page_views, e.page_views
|
38
|
+
assert_equal page_views, e.entry_metadata.page_views
|
39
|
+
end
|
40
|
+
end
|
data/test/setup.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_record/fixtures'
|
4
|
+
require 'attribute_delegator'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
ActiveRecord::Base.establish_connection({
|
8
|
+
:adapter => 'sqlite3',
|
9
|
+
:database => 'test/attribute_delegator_test.db',
|
10
|
+
:dbfile => 'test.db'
|
11
|
+
})
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define do
|
14
|
+
create_table "entries", :force => true do |t|
|
15
|
+
t.column "title", :string
|
16
|
+
t.column "body", :text
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table "entry_metadata", :force => true do |t|
|
20
|
+
t.column "entry_id", :integer
|
21
|
+
t.column "page_views", :integer
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table "entry_photos", :force => true do |t|
|
25
|
+
t.column "entry_id", :integer
|
26
|
+
t.column "photo", :text
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attribute_delegator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Clif Reeder
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-01-16 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activerecord
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 19
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 3
|
33
|
+
- 8
|
34
|
+
version: 2.3.8
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: activesupport
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 19
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 3
|
49
|
+
- 8
|
50
|
+
version: 2.3.8
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: sqlite3
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
type: :development
|
66
|
+
version_requirements: *id003
|
67
|
+
description: AttributeDelegator provides a class method to ActiveRecord models that dynamically generates getter/setter to treat the attributes of a has_one model like native attributes. This is particularly useful because it allows the delegated attributes to be assigned via model.attributes= {}, such as by a form submission.
|
68
|
+
email:
|
69
|
+
- clif@voxmedia.com
|
70
|
+
executables: []
|
71
|
+
|
72
|
+
extensions: []
|
73
|
+
|
74
|
+
extra_rdoc_files: []
|
75
|
+
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Gemfile
|
79
|
+
- README.markdown
|
80
|
+
- Rakefile
|
81
|
+
- attribute_delegator.gemspec
|
82
|
+
- lib/attribute_delegator.rb
|
83
|
+
- lib/attribute_delegator/version.rb
|
84
|
+
- test/attribute_delegator_test.rb
|
85
|
+
- test/multiple_attribute_delegator_test.rb
|
86
|
+
- test/setup.rb
|
87
|
+
has_rdoc: true
|
88
|
+
homepage: ""
|
89
|
+
licenses: []
|
90
|
+
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
114
|
+
requirements: []
|
115
|
+
|
116
|
+
rubyforge_project: attribute_delegator
|
117
|
+
rubygems_version: 1.3.7
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: ActiveRecord extension that allows you to treat fields from another model/table as local attributes.
|
121
|
+
test_files:
|
122
|
+
- test/attribute_delegator_test.rb
|
123
|
+
- test/multiple_attribute_delegator_test.rb
|
124
|
+
- test/setup.rb
|