attribute-defaults 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ spec/tmp
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :test do
4
+ gem 'activerecord', '3.0.0'
5
+ gem 'activesupport', '3.0.0'
6
+ gem "sqlite3-ruby"
7
+ gem "rspec", "~> 2.0.0.beta"
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.0.0)
5
+ activesupport (= 3.0.0)
6
+ builder (~> 2.1.2)
7
+ i18n (~> 0.4.1)
8
+ activerecord (3.0.0)
9
+ activemodel (= 3.0.0)
10
+ activesupport (= 3.0.0)
11
+ arel (~> 1.0.0)
12
+ tzinfo (~> 0.3.23)
13
+ activesupport (3.0.0)
14
+ arel (1.0.1)
15
+ activesupport (~> 3.0.0)
16
+ builder (2.1.2)
17
+ diff-lcs (1.1.2)
18
+ i18n (0.4.1)
19
+ rspec (2.0.0.beta.22)
20
+ rspec-core (= 2.0.0.beta.22)
21
+ rspec-expectations (= 2.0.0.beta.22)
22
+ rspec-mocks (= 2.0.0.beta.22)
23
+ rspec-core (2.0.0.beta.22)
24
+ rspec-expectations (2.0.0.beta.22)
25
+ diff-lcs (>= 1.1.2)
26
+ rspec-mocks (2.0.0.beta.22)
27
+ rspec-core (= 2.0.0.beta.22)
28
+ rspec-expectations (= 2.0.0.beta.22)
29
+ sqlite3-ruby (1.3.1)
30
+ tzinfo (0.3.23)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ activerecord (= 3.0.0)
37
+ activesupport (= 3.0.0)
38
+ rspec (~> 2.0.0.beta)
39
+ sqlite3-ruby
data/README.rdoc ADDED
@@ -0,0 +1,110 @@
1
+ = Attribute Defaults (attribute-defaults)
2
+
3
+ Simple ActiveRecord plugin that allows to specify default values for attributes.
4
+
5
+ == Installation
6
+
7
+ Just add <tt>gem attribute-defaults</tt> to your Gemfile.
8
+
9
+ Alternatively, run <tt>sudo gem install attribute-defaults</tt> and add
10
+ <tt>require 'attribute_defaults'</tt> to your app.
11
+
12
+ == Examples
13
+
14
+ First, a simple case ...
15
+
16
+ class Foo < ActiveRecord::Base
17
+ attr_default :age, 18
18
+ attr_default :last_seen do
19
+ Time.now
20
+ end
21
+ end
22
+ Foo.new # => age: 18, last_seen: '2010-09-15 10:30'
23
+
24
+ ... or the same via mass-definition ...
25
+
26
+ class Foo < ActiveRecord::Base
27
+ attr_defaults :age => 18, :last_seen => lambda { Time.now }
28
+ end
29
+ Foo.new # => age: 18, last_seen: '2010-09-15 10:30'
30
+
31
+ It doesn't override values that are already set ...
32
+
33
+ class Foo < ActiveRecord::Base
34
+ attr_defaults :age => 18
35
+ end
36
+ Foo.new(:age => 25) # => age: 25
37
+
38
+ ... but allows you to force overrides when e.g. blank ...
39
+
40
+ class Foo < ActiveRecord::Base
41
+ attr_defaults :name => { :default => 'MUST HAVE', :force => :blank }
42
+ end
43
+ Foo.new(:name => '') # => name: 'MUST HAVE'
44
+
45
+ ... and it respects protected attributes ...
46
+
47
+ class Foo < ActiveRecord::Base
48
+ attr_protected :age
49
+ attr_defaults :age => 18
50
+ end
51
+ Foo.new(:age => 25) # => age: 18
52
+
53
+ When attributes aren't database columns ...
54
+
55
+ class Foo < ActiveRecord::Base
56
+ attr_accessor :birth_year
57
+ attr_defaults :birth_year => lambda {|r| r.age ? Time.now.year - r.age : nil }
58
+ end
59
+ Foo.new(:age => 30) # => age: 30, birth_year: 1980
60
+
61
+ It works with persisted records ...
62
+
63
+ # DB table 'foos': [{id: 1, age: NULL}, {id: 2, age: 25}]
64
+ class Foo < ActiveRecord::Base
65
+ attr_defaults :age => 18
66
+ end
67
+ Foo.all # => [{id: 1, age: 18}, {id: 2, age: 25}]
68
+
69
+ ... or not ...
70
+
71
+ class Foo < ActiveRecord::Base
72
+ attr_defaults :age => { :default => 18, :persisted => false }
73
+ end
74
+ Foo.all # => [{id: 1, age: nil}, {id: 2, age: 25}]
75
+
76
+ To specify a Hash as a default value, use ...
77
+
78
+ class Foo < ActiveRecord::Base
79
+ attr_accessor :some_hash
80
+ attr_default :some_hash, :default => {}
81
+ end
82
+ Foo.new.some_hash # => {}
83
+
84
+ == Acknowledgements
85
+
86
+ Inspired by the default_value_for plugin
87
+ http://github.com/FooBarWidget/default_value_for
88
+
89
+ = LICENSE
90
+
91
+ (The MIT License)
92
+
93
+ Permission is hereby granted, free of charge, to any person obtaining
94
+ a copy of this software and associated documentation files (the
95
+ 'Software'), to deal in the Software without restriction, including
96
+ without limitation the rights to use, copy, modify, merge, publish,
97
+ distribute, sublicense, and/or sell copies of the Software, and to
98
+ permit persons to whom the Software is furnished to do so, subject to
99
+ the following conditions:
100
+
101
+ The above copyright notice and this permission notice shall be
102
+ included in all copies or substantial portions of the Software.
103
+
104
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
105
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
106
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
107
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
108
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
109
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
110
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require 'rake'
2
+ require 'rspec/mocks/version'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ desc 'Default: run specs.'
8
+ task :default => :spec
9
+
10
+ begin
11
+ require 'jeweler'
12
+ Jeweler::Tasks.new do |gemspec|
13
+ gemspec.name = "attribute-defaults"
14
+ gemspec.summary = "Specify default values for attributes"
15
+ gemspec.description = "Simple ActiveRecord plugin that allows to specify default values for attributes"
16
+ gemspec.email = "dimitrij@blacksquaremedia.com"
17
+ gemspec.homepage = "http://github.com/bsm/attribute-defaults"
18
+ gemspec.authors = ["Dimitrij Denissenko"]
19
+ gemspec.add_runtime_dependency "activerecord", ">= 3.0.0"
20
+ gemspec.add_runtime_dependency "activesupport", ">= 3.0.0"
21
+ end
22
+ Jeweler::GemcutterTasks.new
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
25
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1 @@
1
+ require 'attribute_defaults'
@@ -0,0 +1,57 @@
1
+ module ActiveRecord
2
+ module AttributesWithDefaults
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ # Set defaults. Examples:
8
+ # attr_default :age, 12
9
+ # attr_default :description, '(none)'
10
+ # attr_default :age do |record|
11
+ # Time.zone.year - record.dob.year
12
+ # end
13
+ # attr_default :description, '(none)', :if => :blank
14
+ # attr_default :description, '(none)', :persisted => false
15
+ # attr_default :description, :default => '(none)', :persisted => false
16
+ def attr_default(sym, *args, &block)
17
+ options = args.extract_options!
18
+ default = options.delete(:default) || args.shift
19
+ raise 'Default value or block required' unless !default.nil? || block
20
+
21
+ evaluator = "__eval_attr_default_for_#{sym}".to_sym
22
+ setter = "__set_attr_default_for_#{sym}".to_sym
23
+ block ||= default.is_a?(Proc) ? default : Proc.new { default }
24
+
25
+ after_initialize setter.to_sym
26
+ define_method(evaluator, &block)
27
+
28
+ module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
29
+ def #{setter}
30
+ #{'return if persisted?' if options[:persisted] == false}
31
+ return unless self.#{sym}.send(#{options[:force] == :blank ? ':blank?' : ':nil?'})
32
+ value = #{evaluator}(self)
33
+ self.#{sym} = value.duplicable? ? value.dup : value
34
+ rescue ActiveModel::MissingAttributeError
35
+ end
36
+ EVAL
37
+ private evaluator, setter
38
+ end
39
+
40
+ # Default mass-assignment. Examples:
41
+ # attr_defaults :description => '(none)', :age => 12
42
+ # attr_defaults :description => '(none)', :age => lambda {|r| Time.zone.year - r.dob.year }
43
+ # attr_defaults :description => '(none)', :age => { :default => 12, :persisted => false }
44
+ def attr_defaults(pairs)
45
+ pairs.each do |pair|
46
+ attr_default *pair
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ class Base
54
+ include AttributesWithDefaults
55
+ end
56
+
57
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe ActiveRecord::AttributesWithDefaults do
4
+
5
+ def foo(options = {})
6
+ @foo ||= Foo.new options.reverse_merge(:age => 30)
7
+ end
8
+
9
+ def bar(options = {})
10
+ @bar ||= Bar.new options.reverse_merge(:age => 30)
11
+ end
12
+
13
+ def baz(options = {})
14
+ @baz ||= Baz.new
15
+ end
16
+
17
+ it 'should initialize records setting defaults' do
18
+ foo.description.should == '(no description)'
19
+ foo.locale.should == 'en'
20
+ foo.birth_year.should == 30.years.ago.year
21
+ end
22
+
23
+ it 'should allow to foce overrides on blank values' do
24
+ foo(:locale => '', :description => '')
25
+ foo.locale.should == ''
26
+ foo.description.should == '(no description)'
27
+ end
28
+
29
+ it 'should not override attributes that were set manually' do
30
+ foo(:locale => 'en-GB').locale.should == 'en-GB'
31
+ end
32
+
33
+ it 'should respect :persisted => false option' do
34
+ persisted = Foo.first
35
+ persisted.description.should == '(no description)'
36
+ persisted.locale.should be_nil
37
+ end
38
+
39
+ it 'should work with protected attributes' do
40
+ foo(:description => 'Custom').description.should == '(no description)'
41
+ end
42
+
43
+ it 'should correctly apply defaults in subclasses' do
44
+ bar.description.should == '(no description)'
45
+ bar.locale.should == 'en'
46
+ bar.birth_year.should == 30.years.ago.year
47
+ end
48
+
49
+ it 'should allow mass-assignment' do
50
+ baz.description.should == 'Please set ...'
51
+ baz.locale.should == 'en-US'
52
+ baz.age.should == 18
53
+
54
+ persisted = Baz.first
55
+ persisted.age.should be_nil
56
+ end
57
+
58
+ it 'should allow Hashes as default values' do
59
+ bar.some_hash.should == {}
60
+ end
61
+
62
+ it 'should ensure default values are duplicated' do
63
+ bar.some_hash[:a] = 'A'
64
+ bar.some_hash.should == {:a => 'A'}
65
+ Bar.new.some_hash.should == {}
66
+ end
67
+
68
+ it 'should handle missing attributes (e.g. in case of Base#exists?)' do
69
+ lambda { Foo.exists? }.should_not raise_error
70
+ lambda { Foo.select(:locale).first }.should_not raise_error
71
+ end
72
+
73
+
74
+ end
@@ -0,0 +1,56 @@
1
+ $: << File.dirname(__FILE__) + '/../lib'
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler.setup
5
+ Bundler.require :default, :test
6
+
7
+ require 'active_support'
8
+ require 'active_record'
9
+ require 'rspec'
10
+ require 'fileutils'
11
+ require 'attribute_defaults'
12
+
13
+ SPEC_DATABASE = File.dirname(__FILE__) + '/tmp/test.sqlite3'
14
+
15
+ RSpec.configure do |c|
16
+
17
+ c.before do
18
+ FileUtils.mkdir_p File.dirname(SPEC_DATABASE)
19
+ base = ActiveRecord::Base
20
+ base.establish_connection('adapter' => 'sqlite3', 'database' => SPEC_DATABASE)
21
+ base.connection.create_table :foos do |t|
22
+ t.string :name
23
+ t.integer :age
24
+ t.string :locale
25
+ t.string :description
26
+ t.timestamps
27
+ end
28
+ Foo.create!(:name => 'Bogus') {|f| f.description = nil; f.locale = nil }
29
+ end
30
+
31
+ c.after do
32
+ FileUtils.rm_f(SPEC_DATABASE)
33
+ end
34
+
35
+ end
36
+
37
+ class Foo < ActiveRecord::Base
38
+ attr_accessible :name, :age, :locale
39
+ attr_accessor :birth_year
40
+
41
+ attr_default :description, "(no description)", :force => :blank
42
+ attr_default :locale, "en", :persisted => false
43
+ attr_default :birth_year do |f|
44
+ f.age ? Time.now.year - f.age : nil
45
+ end
46
+ end
47
+
48
+ class Bar < Foo
49
+ attr_accessor :some_hash
50
+ attr_default :some_hash, :default => {}
51
+ end
52
+
53
+ class Baz < ActiveRecord::Base
54
+ set_table_name 'foos'
55
+ attr_defaults :description => "Please set ...", :age => { :default => 18, :persisted => false }, :locale => lambda { 'en-US' }
56
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attribute-defaults
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
+ - Dimitrij Denissenko
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-15 00:00:00 +01: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: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ version: 3.0.0
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: 7
46
+ segments:
47
+ - 3
48
+ - 0
49
+ - 0
50
+ version: 3.0.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ description: Simple ActiveRecord plugin that allows to specify default values for attributes
54
+ email: dimitrij@blacksquaremedia.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files:
60
+ - README.rdoc
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - README.rdoc
66
+ - Rakefile
67
+ - VERSION
68
+ - lib/attribute-defaults.rb
69
+ - lib/attribute_defaults.rb
70
+ - spec/attribute_defaults_spec.rb
71
+ - spec/spec_helper.rb
72
+ has_rdoc: true
73
+ homepage: http://github.com/bsm/attribute-defaults
74
+ licenses: []
75
+
76
+ post_install_message:
77
+ rdoc_options:
78
+ - --charset=UTF-8
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ hash: 3
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.3.7
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Specify default values for attributes
106
+ test_files:
107
+ - spec/attribute_defaults_spec.rb
108
+ - spec/spec_helper.rb