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 ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ test/*.db
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in attribute_delegator.gemspec
4
+ gemspec
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,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ task :default => :test
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'lib'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ t.verbose = true
10
+ end
@@ -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,3 @@
1
+ module AttributeDelegator
2
+ VERSION = "0.0.1"
3
+ 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