attr_inherited 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ test/debug.log
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in attr_inherited.gemspec
4
+ gemspec
@@ -0,0 +1,23 @@
1
+ Copyright (c) Christos Zisopoulos ( [@christos](http://twitter.com/christos) )
2
+ ========================================================================================
3
+
4
+ The "attr_inherited_" plugin is released under the **MIT LICENSE**
5
+ --------------------------------------------------------------------
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
@@ -0,0 +1,145 @@
1
+ ## Description
2
+
3
+ Attribute inheritance for `ActiveRecord` models
4
+
5
+ Using `attr_inherited` allows your `ActiveRecord` models to inherit any of their attributes from an associated, or parent model.
6
+
7
+
8
+
9
+ ## Usage
10
+
11
+ [![Build Status](https://secure.travis-ci.org/christos/attr_inherited.png)](http://travis-ci.org/christos/attr_inherited)
12
+
13
+ ### Inheriting attributes from an associated model
14
+
15
+ Given a `Post` model and the following `Version` model
16
+
17
+ class Version < ActiveRecord::Base
18
+ belongs_to :post
19
+
20
+ attr_inherited :title, :synopsis, from: :post
21
+ end
22
+
23
+ ..then `Version` will now inherit `title` and `synopsis` from the parent post, if either attributes are `nil`
24
+
25
+ 1.9.3p194 :001 > post = Post.create!(title: "First post", synopsis: "First post synopsis")
26
+ 1.9.3p194 :002 > version = Version.create!(post: post)
27
+
28
+ 1.9.3p194 :003 > version.title
29
+ => "First post"
30
+
31
+ 1.9.3p194 :004 > version.body
32
+ => "First post body"
33
+
34
+ You can override any of the inherited attributes by setting its a value to anything other than `nil`
35
+
36
+ 1.9.3p194 :005 > version.update_attributes(description: "Version synopsis")
37
+
38
+ 1.9.3p194 :006 > version.synopsis
39
+ => "Version description"
40
+
41
+ ### Renaming inherited attributes
42
+
43
+ If you want the inherited attribute to have a name other than that of the associated model's attribute, you can use the `as:` option to rename it. For example:
44
+
45
+ class Version < ActiveRecord::Base
46
+ belongs_to :post
47
+
48
+ attr_inherited :synopsis, from: :post, as: :description
49
+ end
50
+
51
+ 1.9.3p194 :001 > post = Post.create!(synopsis: "First post synopsis")
52
+ 1.9.3p194 :002 > version = Version.create!(post: post)
53
+
54
+ 1.9.3p194 :003 > version.description
55
+ => "First post synopsis"
56
+
57
+ Note that `description` must be an attribute of `Version` for the above to work.
58
+
59
+ ### Inheriting attributes even when they are not `nil`
60
+
61
+ You might want to inherit an attribute not only when it is `nil` but even when it is an empty string `""`. You can do this by passing a predicate with the `when:` option that would test if the attribute should be inherited.
62
+
63
+ class Version < ActiveRecord::Base
64
+ belongs_to :post
65
+
66
+ attr_inherited :title, from: :post, when: :blank?
67
+ end
68
+
69
+ 1.9.3p194 :001 > post = Post.create!(title: "First post")
70
+ 1.9.3p194 :002 > version = Version.create!(post: post)
71
+
72
+ 1.9.3p194 :003 > version.title
73
+ => "First post"
74
+
75
+ 1.9.3p194 :004 > version.update_attributes(title: " ")
76
+ 1.9.3p194 :005 > version.title
77
+ => "First post"
78
+
79
+ ### Using the `when:` option to fake has_many association inheritance
80
+
81
+ Until real association inheritance is implemented you can fake it like this:
82
+
83
+ class Version < ActiveRecord::Base
84
+ has_many :comments, as: :commentable
85
+ end
86
+
87
+ class Version < ActiveRecord::Base
88
+ belongs_to :post
89
+ has_many :comments, as: :commentable
90
+
91
+ attr_inherited :comments, from: :post, when: :empty?
92
+ end
93
+
94
+ ...which makes `comments` behave almost as if it was inherited from `Post`:
95
+
96
+ 1.9.3p194 :001 > post = Post.create!(title: "First post")
97
+ 1.9.3p194 :002 > post.comments.create(text: "Post comment")
98
+
99
+ 1.9.3p194 :003 > version = Version.create!(post: post)
100
+ 1.9.3p194 :004 > version.comments.first.text
101
+ => "Post comment"
102
+
103
+ 1.9.3p194 :005 > version.comments = [Comment.create(text: "Version comment")]
104
+ 1.9.3p194 :006 > version.comments.first.text
105
+ => "Version comment"
106
+
107
+ **Caveat**: You can't call any other association methods on `version.comments` when it is inherited, such as `<<`, `.create`, `.build`
108
+
109
+ ## Installation
110
+
111
+ *Requires Rails 3.1+*
112
+
113
+ Add this line to your application's Gemfile:
114
+
115
+ gem 'attr_inherited'
116
+
117
+ And then execute:
118
+
119
+ $ bundle
120
+
121
+ Or install it yourself as:
122
+
123
+ $ gem install attr_inherited
124
+
125
+ ## Changelog
126
+
127
+ **1.0.0** Initial relase (2012-10-02)
128
+
129
+ ## To Do
130
+
131
+ * Test assertion of valid parameters
132
+ * Write rdocs
133
+ * Document or remove default `parent` option for `from:` option
134
+ * Properly support inheriting associations
135
+ * Investigate support for virtual attributes (:attr_accessor)
136
+
137
+ ## Contributing
138
+
139
+ 1. Fork it
140
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
141
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
142
+ 4. Push to the branch (`git push origin my-new-feature`)
143
+ 5. Create new Pull Request
144
+
145
+ Copyright (c) Christos Zisopoulos, released under the MIT license
@@ -0,0 +1,15 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require "bundler/gem_tasks"
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the attr_inherited gem.'
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
+
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'attr_inherited/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "attr_inherited"
8
+ gem.version = AttrInherited::VERSION
9
+
10
+ gem.authors = ["Christos Zisopoulos"]
11
+ gem.email = ["christos@mac.com"]
12
+ gem.description = "Attribute inheritance for ActiveRecord models"
13
+ gem.summary = gem.description
14
+ gem.homepage = "https://github.com/christos/attr_inherited"
15
+
16
+ gem.rubyforge_project = "attr_inherited"
17
+
18
+ gem.files = `git ls-files`.split($/)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.require_paths = ["lib"]
22
+
23
+ gem.add_development_dependency "rake"
24
+ gem.add_development_dependency "sqlite3"
25
+
26
+ gem.add_dependency "activesupport"
27
+ gem.add_dependency "activerecord"
28
+
29
+ end
@@ -0,0 +1,51 @@
1
+ require "attr_inherited/version"
2
+ require 'active_record'
3
+
4
+ module AttrInherited
5
+ def self.included(base) #:nodoc:
6
+ base.extend(AttrInheritedMacro)
7
+ end
8
+
9
+ module AttrInheritedMacro
10
+
11
+ def attr_inherited(*attrs)
12
+ if attrs.last.is_a? Hash
13
+ options = attrs.pop
14
+ end
15
+
16
+ _parent = options[:from] || 'parent'
17
+ _predicate = options[:when] && options[:when].to_s || 'nil?'
18
+
19
+ raise ArgumentError.new("Can't specify :as for multiple attributes in a single line") if attrs.size > 1 && options[:as].present?
20
+
21
+ attrs.each do |attr|
22
+ _alias = options[:as] || attr
23
+
24
+ class_eval <<-END, __FILE__, __LINE__
25
+
26
+ def #{_alias}_before_type_cast
27
+ _super = super
28
+ !_super.#{_predicate} && super || #{_parent} && #{_parent}.#{attr}_before_type_cast
29
+ end
30
+
31
+ def #{_alias}
32
+ _super = super
33
+ !_super.#{_predicate} && _super || #{_parent} && #{_parent}.#{attr} && !#{_parent}.#{attr}.#{_predicate} && #{_parent}.#{attr} || _super
34
+ end
35
+
36
+ def #{_alias}=(value)
37
+ super(value) if #{_parent}.nil? || #{_parent}.#{attr}.#{_predicate} || (#{_parent} && #{_parent}.#{attr} && #{_parent}.#{attr} != value)
38
+ end
39
+
40
+ def #{_alias}_inherited?
41
+ #{_parent}.#{attr} == self.#{attr}
42
+ end
43
+
44
+ END
45
+ end
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ ActiveRecord::Base.send(:include, AttrInherited)
@@ -0,0 +1,3 @@
1
+ module AttrInherited
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,84 @@
1
+ require 'test_helper'
2
+
3
+ class AttributeChoicesTest < ActiveSupport::TestCase
4
+
5
+ class Post < ActiveRecord::Base
6
+ has_many :comments, as: :commentable
7
+ end
8
+
9
+ class Version < ActiveRecord::Base
10
+ belongs_to :post
11
+ has_many :comments, as: :commentable
12
+
13
+ attr_inherited :title, :body, from: :post
14
+ attr_inherited :synopsis, from: :post, as: :description
15
+
16
+ attr_inherited :comments, from: :post, when: :empty?
17
+ end
18
+
19
+ class Comment < ActiveRecord::Base
20
+ belongs_to :commentable, polymorphic: true
21
+ end
22
+
23
+ test "It should add a class method to all ActiveRecord objects" do
24
+ assert_respond_to ActiveRecord::Base, :attr_inherited
25
+ assert_respond_to Post, :attr_inherited
26
+ assert_respond_to Version, :attr_inherited
27
+ assert_respond_to Comment, :attr_inherited
28
+ end
29
+
30
+ test "It does not inherit attributes if its parent object is nil" do
31
+ version = Version.create! author: "Christos Zisopoulos", title: "First post"
32
+
33
+ assert_equal version.title, "First post"
34
+ assert_equal version.body, nil
35
+ assert_equal version.author, "Christos Zisopoulos"
36
+ end
37
+
38
+ test "It inherits attributes from the specified parent association when attribute is nil" do
39
+ post = Post.create! title: "First post", body: "First post body"
40
+ version = Version.create! author: "Christos Zisopoulos", post: post
41
+
42
+ assert_equal version.title, "First post"
43
+ assert_equal version.body, "First post body"
44
+ assert_equal version.author, "Christos Zisopoulos"
45
+ end
46
+
47
+ test "Inherited attribute's name can be aliased" do
48
+ post = Post.create! synopsis: "First post synopsis"
49
+ version = Version.create! post_id: post.id
50
+
51
+ assert_equal version.description, "First post synopsis"
52
+ end
53
+
54
+ test "Overrding the values of inherited attributes" do
55
+ post = Post.create! title: "First post", body: "First post body"
56
+ version = Version.create! do |v|
57
+ v.post_id = post.id
58
+ v.title = "Version title"
59
+ v.body = "Version body"
60
+ v.description = "Version description"
61
+ v.author = "Christos Zisopoulos"
62
+ end
63
+
64
+ assert_equal version.title, "Version title"
65
+ assert_equal version.body, "Version body"
66
+ assert_equal version.description, "Version description"
67
+ assert_equal version.author, "Christos Zisopoulos"
68
+ end
69
+
70
+ test "Using a user defined predicate to decide when to inherit" do
71
+ post = Post.create! title: "First post", body: "First post body"
72
+ post.comments.create! body: "Comment 1"
73
+ version = Version.create! post_id: post.id
74
+
75
+ assert_equal version.comments, post.comments
76
+
77
+ version_comment = Comment.create! body: "Comment 3"
78
+ version.comments = [version_comment]
79
+
80
+ assert_equal version.comments, [version_comment]
81
+ end
82
+
83
+ end
84
+
@@ -0,0 +1,3 @@
1
+ sqlite3mem:
2
+ :adapter: sqlite3
3
+ :database: ":memory:"
@@ -0,0 +1,45 @@
1
+ # This file is auto-generated from the current state of the database. Instead of editing this file,
2
+ # please use the migrations feature of Active Record to incrementally modify your database, and
3
+ # then regenerate this schema definition.
4
+ #
5
+ # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6
+ # to create the application database on another system, you should be using db:schema:load, not running
7
+ # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
9
+ #
10
+ # It's strongly recommended to check this file into your version control system.
11
+
12
+ ActiveRecord::Schema.define(:version => 20090418155608) do
13
+
14
+ create_table "posts", :force => true do |t|
15
+ t.string "title"
16
+ t.text "synopsis"
17
+ t.text "body"
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ end
21
+
22
+ create_table "versions", :force => true do |t|
23
+ t.integer "post_id"
24
+
25
+ t.string "title"
26
+ t.text "description"
27
+ t.text "body"
28
+ t.string "author"
29
+
30
+ t.datetime "created_at"
31
+ t.datetime "updated_at"
32
+ end
33
+
34
+ create_table "comments", :force => true do |t|
35
+ t.integer "commentable_id"
36
+ t.string "commentable_type"
37
+
38
+ t.text "body"
39
+ t.string "author"
40
+
41
+ t.datetime "created_at"
42
+ t.datetime "updated_at"
43
+ end
44
+
45
+ end
@@ -0,0 +1,19 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+
3
+ require 'rubygems'
4
+
5
+ require 'attr_inherited'
6
+
7
+ require 'test/unit'
8
+
9
+ require 'active_support/test_case'
10
+ require 'active_record/fixtures'
11
+
12
+
13
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
14
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
15
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite3mem'])
16
+
17
+ ActiveRecord::Migration.verbose = false
18
+ load(File.dirname(__FILE__) + "/schema.rb")
19
+
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attr_inherited
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Christos Zisopoulos
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: sqlite3
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: activesupport
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: activerecord
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Attribute inheritance for ActiveRecord models
79
+ email:
80
+ - christos@mac.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - attr_inherited.gemspec
91
+ - lib/attr_inherited.rb
92
+ - lib/attr_inherited/version.rb
93
+ - test/attr_inherited_test.rb
94
+ - test/database.yml
95
+ - test/schema.rb
96
+ - test/test_helper.rb
97
+ homepage: https://github.com/christos/attr_inherited
98
+ licenses: []
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project: attr_inherited
117
+ rubygems_version: 1.8.24
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Attribute inheritance for ActiveRecord models
121
+ test_files:
122
+ - test/attr_inherited_test.rb
123
+ - test/database.yml
124
+ - test/schema.rb
125
+ - test/test_helper.rb