ancestree 0.1.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/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'rake'
4
+ gem 'bundler', '1.0.0.rc.5'
5
+ gem 'activesupport', '3.0.0.rc'
6
+ gem 'activerecord', '3.0.0.rc'
7
+ gem "rspec", '2.0.0.beta.19'
8
+
9
+ gem 'jeweler'
data/Gemfile.lock ADDED
@@ -0,0 +1,48 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.0.0.rc)
5
+ activesupport (= 3.0.0.rc)
6
+ builder (~> 2.1.2)
7
+ i18n (~> 0.4.1)
8
+ activerecord (3.0.0.rc)
9
+ activemodel (= 3.0.0.rc)
10
+ activesupport (= 3.0.0.rc)
11
+ arel (~> 0.4.0)
12
+ tzinfo (~> 0.3.22)
13
+ activesupport (3.0.0.rc)
14
+ arel (0.4.0)
15
+ activesupport (>= 3.0.0.beta)
16
+ builder (2.1.2)
17
+ diff-lcs (1.1.2)
18
+ gemcutter (0.6.1)
19
+ git (1.2.5)
20
+ i18n (0.4.1)
21
+ jeweler (1.4.0)
22
+ gemcutter (>= 0.1.0)
23
+ git (>= 1.2.5)
24
+ rubyforge (>= 2.0.0)
25
+ json_pure (1.4.6)
26
+ rake (0.8.7)
27
+ rspec (2.0.0.beta.19)
28
+ rspec-core (= 2.0.0.beta.19)
29
+ rspec-expectations (= 2.0.0.beta.19)
30
+ rspec-mocks (= 2.0.0.beta.19)
31
+ rspec-core (2.0.0.beta.19)
32
+ rspec-expectations (2.0.0.beta.19)
33
+ diff-lcs (>= 1.1.2)
34
+ rspec-mocks (2.0.0.beta.19)
35
+ rubyforge (2.0.4)
36
+ json_pure (>= 1.1.7)
37
+ tzinfo (0.3.23)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ activerecord (= 3.0.0.rc)
44
+ activesupport (= 3.0.0.rc)
45
+ bundler (= 1.0.0.rc.5)
46
+ jeweler
47
+ rake
48
+ rspec (= 2.0.0.beta.19)
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,23 @@
1
+ Ancestree
2
+ =========
3
+
4
+ Ancestree is a simple Rails 3 plugin that makes it easy to automatically inherit attributes from a parent object.
5
+
6
+ Ancestree makes a few assumptions about the objects that will be inheriting attributes -- namely, objects should be in a tree-like structure, with each object responding to '#parent' up the tree, with the top-level objects returning nil for parent.
7
+
8
+
9
+ Example
10
+ =======
11
+
12
+ Let's assume you have a Node model in your Rails app and that Node objects each have a parent. You want Nodes to be "disabled" if it or any of its parents are disabled:
13
+
14
+ class Node < ActiveRecord::Base
15
+ include InheritAncestorAttributes
16
+
17
+ belongs_to :parent, :class_name => 'Node'
18
+
19
+ inherit_ancestor_attributes :disabled?
20
+ end
21
+
22
+
23
+ Copyright (c) 2010 Brian Rose, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the ancestree plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the ancestree plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Ancestree'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ begin
26
+ require 'jeweler'
27
+ Jeweler::Tasks.new do |gemspec|
28
+ gemspec.name = "ancestree"
29
+ gemspec.summary = "Rails 3 plugin to inherit attributes"
30
+ gemspec.description = "Ancestree is a Rails 3 plugin that makes inheriting properties from parent objects in tree-like structure simple."
31
+ gemspec.email = "brian@heimidal.net"
32
+ gemspec.homepage = "http://github.com/heimidal/ancestree"
33
+ gemspec.authors = ["Brian Rose", "Gabe Varela"]
34
+ gemspec.add_development_dependency('rspec', '2.0.0.beta.19')
35
+ gemspec.add_dependency('activesupport', '>= 3.0.0.rc')
36
+ gemspec.add_dependency('activerecord', '>= 3.0.0.rc')
37
+ end
38
+ rescue LoadError
39
+ puts "Jeweler not available. Install it with: gem install jeweler"
40
+ end
41
+
42
+ Jeweler::GemcutterTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/ancestree.gemspec ADDED
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ancestree}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Brian Rose", "Gabe Varela"]
12
+ s.date = %q{2010-08-20}
13
+ s.description = %q{Ancestree is a Rails 3 plugin that makes inheriting properties from parent objects in tree-like structure simple.}
14
+ s.email = %q{brian@heimidal.net}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ "Gemfile",
20
+ "Gemfile.lock",
21
+ "MIT-LICENSE",
22
+ "README",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "ancestree.gemspec",
26
+ "init.rb",
27
+ "install.rb",
28
+ "lib/ancestree.rb",
29
+ "spec/inherit_ancestor_attributes_spec.rb",
30
+ "spec/spec_helper.rb",
31
+ "uninstall.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/heimidal/ancestree}
34
+ s.rdoc_options = ["--charset=UTF-8"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.3.7}
37
+ s.summary = %q{Rails 3 plugin to inherit attributes}
38
+ s.test_files = [
39
+ "spec/inherit_ancestor_attributes_spec.rb",
40
+ "spec/spec_helper.rb"
41
+ ]
42
+
43
+ if s.respond_to? :specification_version then
44
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ s.add_development_dependency(%q<rspec>, ["= 2.0.0.beta.19"])
49
+ s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0.rc"])
50
+ s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0.rc"])
51
+ else
52
+ s.add_dependency(%q<rspec>, ["= 2.0.0.beta.19"])
53
+ s.add_dependency(%q<activesupport>, [">= 3.0.0.rc"])
54
+ s.add_dependency(%q<activerecord>, [">= 3.0.0.rc"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<rspec>, ["= 2.0.0.beta.19"])
58
+ s.add_dependency(%q<activesupport>, [">= 3.0.0.rc"])
59
+ s.add_dependency(%q<activerecord>, [">= 3.0.0.rc"])
60
+ end
61
+ end
62
+
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'ancestree'
2
+
3
+ class ActiveRecord::Base
4
+ include InheritAncestorAttributes
5
+ end
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
data/lib/ancestree.rb ADDED
@@ -0,0 +1,43 @@
1
+ module InheritAncestorAttributes
2
+ extend ActiveSupport::Concern
3
+
4
+ def inherits_from_ancestor?(method)
5
+ !gets_value_locally?(method)
6
+ end
7
+
8
+ private
9
+
10
+ def gets_value_locally?(method)
11
+ send("#{method}_without_parent") == send(method)
12
+ end
13
+
14
+ module ClassMethods
15
+ @@inherit_ancestor_attributes = []
16
+
17
+ def inherit_ancestor_attributes(*attrs)
18
+ self.define_attribute_methods
19
+ attrs.each do |attr|
20
+ create_inheritable_method(attr)
21
+ @@inherit_ancestor_attributes << attr.to_sym
22
+ method_added(attr) if method_defined?(attr)
23
+ end
24
+ end
25
+
26
+ def create_inheritable_method(attribute)
27
+ name = attribute.to_s.gsub(/(\?|!)/, '')
28
+ define_method "#{name}_with_parent#{$1}".to_sym do
29
+ val = send("#{name}_without_parent#{$1}") || parent.try(attribute.to_sym)
30
+ val ||= send("default_#{name}") if respond_to?("default_#{name}")
31
+ val
32
+ end
33
+ end
34
+
35
+ def method_added(name)
36
+ if defined?(:@@inherit_ancestor_attributes) && @@inherit_ancestor_attributes.include?(name)
37
+ @@inherit_ancestor_attributes.delete(name)
38
+ alias_method_chain name, :parent
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,163 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ module MockConcern
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ inherit_ancestor_attributes :some_method
8
+ end
9
+
10
+ def mixin_name
11
+ "mixin_name #{self.name}" if self.name
12
+ end
13
+ end
14
+
15
+ class MockTreeNode
16
+ def self.define_attribute_methods
17
+ attr_accessor :age
18
+ end
19
+
20
+ include InheritAncestorAttributes
21
+ include MockConcern
22
+
23
+ inherit_ancestor_attributes :name, :age, :company, :active?, :bang!
24
+ attr_accessor :name, :company, :active, :bang
25
+
26
+ attr_accessor :parent
27
+
28
+ def default_company
29
+ "Apple"
30
+ end
31
+
32
+ def active?
33
+ active
34
+ end
35
+
36
+ def bang!
37
+ bang
38
+ end
39
+ end
40
+
41
+ class OtherMockClass
42
+ def self.define_attribute_methods
43
+ attr_accessor :name, :other_attr
44
+ end
45
+
46
+ include InheritAncestorAttributes
47
+ include MockConcern
48
+
49
+ inherit_ancestor_attributes :name, :other_attr
50
+
51
+ attr_accessor :parent
52
+ end
53
+
54
+ describe InheritAncestorAttributes do
55
+ context "with parent" do
56
+ subject { node = MockTreeNode.new; node.parent = MockTreeNode.new; node }
57
+
58
+ it "inherits a defined method declared in the base class" do
59
+ subject.parent.name = "Bob"
60
+ subject.name.should == "Bob"
61
+ end
62
+
63
+ it "returns set value of defined method declared in the base class" do
64
+ subject.parent.name = "Bob"
65
+ subject.name = "Rich"
66
+ subject.name.should == "Rich"
67
+ end
68
+
69
+ it "inherits a defined method declared in a mixin" do
70
+ subject.parent.name = "Paul"
71
+ subject.mixin_name.should == "mixin_name Paul"
72
+ end
73
+
74
+ it "returns set value for defined method declared in a mixin" do
75
+ subject.parent.name = "Paul"
76
+ subject.name = "Max"
77
+ subject.mixin_name.should == "mixin_name Max"
78
+ end
79
+
80
+ it "inherits an attribute that is lazy-loaded by Rails" do
81
+ subject.parent.instance_variable_set(:@age, 16)
82
+ subject.age.should == 16
83
+ end
84
+
85
+ it "has a default" do
86
+ subject.company.should == "Apple"
87
+ end
88
+
89
+ it "tells us it inherits the value from its parent" do
90
+ subject.parent.name = "Joe"
91
+ subject.inherits_from_ancestor?(:name).should be_true
92
+ end
93
+
94
+ it "tells us it doesn't inherit the value from its parent" do
95
+ subject.parent.name = "Joe"
96
+ subject.name = "Ken"
97
+ subject.inherits_from_ancestor?(:name).should be_false
98
+ end
99
+
100
+ it "tells us it doesn't inherit the value from its parent when the values are the same" do
101
+ subject.parent.name = "Bill"
102
+ subject.name = "Bill"
103
+ subject.inherits_from_ancestor?(:name).should be_false
104
+ end
105
+
106
+ it "inherits properly when a question mark exists in the method name" do
107
+ subject.parent.active = true
108
+ subject.should be_active
109
+ subject.should respond_to(:active_with_parent?)
110
+ end
111
+
112
+ it "inherits properly when a bang exists in the method name" do
113
+ subject.parent.bang = true
114
+ subject.bang!.should be_true
115
+ subject.should respond_to(:bang_with_parent!)
116
+ end
117
+ end
118
+
119
+ context "without parent" do
120
+ subject { MockTreeNode.new }
121
+
122
+ it "returns the value of a defined method declared in the base class" do
123
+ subject.name = "Bob"
124
+ subject.name.should == "Bob"
125
+ end
126
+
127
+ it "returns the value of a defined method declared in a mixin" do
128
+ subject.name = "Paul"
129
+ subject.name.should == "Paul"
130
+ end
131
+
132
+ it "returns the value of an attribute lazy-loaded by Rails" do
133
+ subject.age = 25
134
+ subject.age.should == 25
135
+ end
136
+
137
+ it "returns the set value even if default exists" do
138
+ subject.company = "Factory Labs"
139
+ subject.company.should == "Factory Labs"
140
+ end
141
+
142
+ it "has a default" do
143
+ subject.company.should == "Apple"
144
+ end
145
+ end
146
+
147
+ context 'with multiple inheriting classes' do
148
+ before do
149
+ @node_1 = MockTreeNode.new
150
+ @node_2 = OtherMockClass.new
151
+ end
152
+
153
+ it "should not inherit attrs that aren't part of the specified class" do
154
+ lambda { @node_1.other_attr }.should raise_error
155
+ lambda { @node_2.other_attr }.should_not raise_error
156
+ end
157
+
158
+ it "should not inherit attrs that aren't part of the specified class (2)" do
159
+ lambda { @node_1.age }.should_not raise_error
160
+ lambda { @node_2.age }.should raise_error
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,31 @@
1
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
+ # from the project root directory.
3
+
4
+ #ENV["RAILS_ENV"] = 'test'
5
+ ENV["RACK_ENV"] = 'test'
6
+
7
+ require 'active_support'
8
+ require 'active_record'
9
+ require File.expand_path("../../init", __FILE__)
10
+
11
+ # Requires supporting files with custom matchers and macros, etc,
12
+ # in ./support/ and its subdirectories.
13
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
14
+
15
+ RSpec.configure do |config|
16
+ # == Mock Framework
17
+ #
18
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
19
+ #
20
+ # config.mock_with :mocha
21
+ # config.mock_with :flexmock
22
+ # config.mock_with :rr
23
+ config.mock_with :rspec
24
+
25
+ # We are using factory_girl_rails instead of fixtures
26
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
27
+
28
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
29
+ # examples within a transaction, comment the following line or assign false
30
+ # instead of true.
31
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ancestree
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Brian Rose
14
+ - Gabe Varela
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-08-20 00:00:00 -06:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rspec
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - "="
29
+ - !ruby/object:Gem::Version
30
+ hash: 62196421
31
+ segments:
32
+ - 2
33
+ - 0
34
+ - 0
35
+ - beta
36
+ - 19
37
+ version: 2.0.0.beta.19
38
+ type: :development
39
+ version_requirements: *id001
40
+ - !ruby/object:Gem::Dependency
41
+ name: activesupport
42
+ prerelease: false
43
+ requirement: &id002 !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ hash: 7712042
49
+ segments:
50
+ - 3
51
+ - 0
52
+ - 0
53
+ - rc
54
+ version: 3.0.0.rc
55
+ type: :runtime
56
+ version_requirements: *id002
57
+ - !ruby/object:Gem::Dependency
58
+ name: activerecord
59
+ prerelease: false
60
+ requirement: &id003 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ hash: 7712042
66
+ segments:
67
+ - 3
68
+ - 0
69
+ - 0
70
+ - rc
71
+ version: 3.0.0.rc
72
+ type: :runtime
73
+ version_requirements: *id003
74
+ description: Ancestree is a Rails 3 plugin that makes inheriting properties from parent objects in tree-like structure simple.
75
+ email: brian@heimidal.net
76
+ executables: []
77
+
78
+ extensions: []
79
+
80
+ extra_rdoc_files:
81
+ - README
82
+ files:
83
+ - Gemfile
84
+ - Gemfile.lock
85
+ - MIT-LICENSE
86
+ - README
87
+ - Rakefile
88
+ - VERSION
89
+ - ancestree.gemspec
90
+ - init.rb
91
+ - install.rb
92
+ - lib/ancestree.rb
93
+ - spec/inherit_ancestor_attributes_spec.rb
94
+ - spec/spec_helper.rb
95
+ - uninstall.rb
96
+ has_rdoc: true
97
+ homepage: http://github.com/heimidal/ancestree
98
+ licenses: []
99
+
100
+ post_install_message:
101
+ rdoc_options:
102
+ - --charset=UTF-8
103
+ require_paths:
104
+ - lib
105
+ required_ruby_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
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ requirements: []
124
+
125
+ rubyforge_project:
126
+ rubygems_version: 1.3.7
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: Rails 3 plugin to inherit attributes
130
+ test_files:
131
+ - spec/inherit_ancestor_attributes_spec.rb
132
+ - spec/spec_helper.rb