dm-accepts_nested_attributes_for 1.2.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.
Files changed (58) hide show
  1. data/CHANGELOG +970 -0
  2. data/Gemfile +84 -0
  3. data/LICENSE +20 -0
  4. data/README.textile +94 -0
  5. data/Rakefile +25 -0
  6. data/TODO +6 -0
  7. data/VERSION +1 -0
  8. data/dm-accepts_nested_attributes.gemspec +114 -0
  9. data/lib/dm-accepts_nested_attributes.rb +13 -0
  10. data/lib/dm-accepts_nested_attributes/model.rb +144 -0
  11. data/lib/dm-accepts_nested_attributes/relationship.rb +82 -0
  12. data/lib/dm-accepts_nested_attributes/resource.rb +382 -0
  13. data/lib/dm-accepts_nested_attributes/version.rb +7 -0
  14. data/spec/accepts_nested_attributes_for_spec.rb +408 -0
  15. data/spec/assign_nested_attributes_for_spec.rb +101 -0
  16. data/spec/comb/1-1_disjoint_spec.rb +67 -0
  17. data/spec/comb/1-1_overlapping_spec.rb +66 -0
  18. data/spec/comb/1-1_subset_spec.rb +65 -0
  19. data/spec/comb/1-1_superset_spec.rb +67 -0
  20. data/spec/comb/1-m_disjoint_spec.rb +71 -0
  21. data/spec/comb/1-m_overlapping_spec.rb +70 -0
  22. data/spec/comb/1-m_subset_spec.rb +65 -0
  23. data/spec/comb/1-m_superset_spec.rb +71 -0
  24. data/spec/comb/m-1_disjoint_spec.rb +71 -0
  25. data/spec/comb/m-1_overlapping_spec.rb +70 -0
  26. data/spec/comb/m-1_subset_spec.rb +65 -0
  27. data/spec/comb/m-1_superset_spec.rb +71 -0
  28. data/spec/comb/n-m_composite_spec.rb +141 -0
  29. data/spec/comb/n-m_surrogate_spec.rb +154 -0
  30. data/spec/many_to_many_composite_spec.rb +120 -0
  31. data/spec/many_to_many_spec.rb +129 -0
  32. data/spec/many_to_one_composite_spec.rb +120 -0
  33. data/spec/many_to_one_spec.rb +101 -0
  34. data/spec/one_to_many_composite_spec.rb +120 -0
  35. data/spec/one_to_many_spec.rb +100 -0
  36. data/spec/one_to_one_composite_spec.rb +150 -0
  37. data/spec/one_to_one_spec.rb +115 -0
  38. data/spec/rcov.opts +6 -0
  39. data/spec/resource_spec.rb +65 -0
  40. data/spec/shared/many_to_many_composite_spec.rb +149 -0
  41. data/spec/shared/many_to_many_spec.rb +146 -0
  42. data/spec/shared/many_to_one_composite_spec.rb +160 -0
  43. data/spec/shared/many_to_one_spec.rb +130 -0
  44. data/spec/shared/one_to_many_composite_spec.rb +159 -0
  45. data/spec/shared/one_to_many_spec.rb +107 -0
  46. data/spec/shared/one_to_one_composite_spec.rb +114 -0
  47. data/spec/shared/one_to_one_spec.rb +111 -0
  48. data/spec/spec.opts +4 -0
  49. data/spec/spec_helper.rb +50 -0
  50. data/spec/update_dirty_spec.rb +113 -0
  51. data/spec/update_multiple_spec.rb +79 -0
  52. data/tasks/changelog.rake +20 -0
  53. data/tasks/ci.rake +1 -0
  54. data/tasks/local_gemfile.rake +18 -0
  55. data/tasks/spec.rake +22 -0
  56. data/tasks/yard.rake +9 -0
  57. data/tasks/yardstick.rake +19 -0
  58. metadata +216 -0
data/Gemfile ADDED
@@ -0,0 +1,84 @@
1
+ source 'http://rubygems.org'
2
+
3
+ SOURCE = ENV.fetch('SOURCE', :git).to_sym
4
+ REPO_POSTFIX = SOURCE == :path ? '' : '.git'
5
+ DATAMAPPER = SOURCE == :path ? Pathname(__FILE__).dirname.parent : 'http://github.com/datamapper'
6
+ DM_VERSION = '~> 1.2.0.rc2'
7
+ DO_VERSION = '~> 0.10.6'
8
+ DM_DO_ADAPTERS = %w[ sqlite postgres mysql oracle sqlserver ]
9
+ CURRENT_BRANCH = ENV.fetch('GIT_BRANCH', 'master')
10
+
11
+ gem 'dm-core', DM_VERSION,
12
+ SOURCE => "#{DATAMAPPER}/dm-core#{REPO_POSTFIX}",
13
+ :branch => CURRENT_BRANCH
14
+
15
+ group :development do
16
+
17
+ gem 'dm-validations', DM_VERSION,
18
+ SOURCE => "#{DATAMAPPER}/dm-validations#{REPO_POSTFIX}",
19
+ :branch => CURRENT_BRANCH
20
+
21
+ gem 'dm-constraints', DM_VERSION,
22
+ SOURCE => "#{DATAMAPPER}/dm-constraints#{REPO_POSTFIX}",
23
+ :branch => CURRENT_BRANCH
24
+
25
+ gem 'rake', '~> 0.9.2'
26
+ gem 'rspec', '~> 1.3.2'
27
+ gem 'yard', '~> 0.7.2'
28
+ gem 'jeweler', '~> 1.6.4'
29
+
30
+ end
31
+
32
+ platforms :mri_18 do
33
+ group :quality do
34
+
35
+ gem 'rcov', '~> 0.9.10'
36
+ gem 'yard', '~> 0.7.2'
37
+ gem 'yardstick', '~> 0.4'
38
+
39
+ end
40
+ end
41
+
42
+ group :datamapper do
43
+
44
+ adapters = ENV['ADAPTER'] || ENV['ADAPTERS']
45
+ adapters = adapters.to_s.tr(',', ' ').split.uniq - %w[ in_memory ]
46
+
47
+ if (do_adapters = DM_DO_ADAPTERS & adapters).any?
48
+
49
+ do_options = {}
50
+ do_options[:git] = "#{DATAMAPPER}/do#{REPO_POSTFIX}" if ENV['DO_GIT'] == 'true'
51
+
52
+ gem 'data_objects', DO_VERSION, do_options.dup
53
+
54
+ do_adapters.each do |adapter|
55
+ adapter = 'sqlite3' if adapter == 'sqlite'
56
+ gem "do_#{adapter}", DO_VERSION, do_options.dup
57
+ end
58
+
59
+ gem 'dm-do-adapter', DM_VERSION,
60
+ SOURCE => "#{DATAMAPPER}/dm-do-adapter#{REPO_POSTFIX}",
61
+ :branch => CURRENT_BRANCH
62
+
63
+ end
64
+
65
+ adapters.each do |adapter|
66
+
67
+ gem "dm-#{adapter}-adapter", DM_VERSION,
68
+ SOURCE => "#{DATAMAPPER}/dm-#{adapter}-adapter#{REPO_POSTFIX}",
69
+ :branch => CURRENT_BRANCH
70
+
71
+ end
72
+
73
+ plugins = ENV['PLUGINS'] || ENV['PLUGIN']
74
+ plugins = plugins.to_s.tr(',', ' ').split.push('dm-migrations').uniq
75
+
76
+ plugins.each do |plugin|
77
+
78
+ gem plugin, DM_VERSION,
79
+ SOURCE => "#{DATAMAPPER}/#{plugin}#{REPO_POSTFIX}",
80
+ :branch => CURRENT_BRANCH
81
+
82
+ end
83
+
84
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Martin Gamsjäger
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.
@@ -0,0 +1,94 @@
1
+ h2. dm-accepts_nested_attributes
2
+
3
+ A DataMapper plugin that allows nested model attribute assignment like activerecord does.
4
+
5
+ Current documentation can always be found at "rdoc.info":http://rdoc.info/projects/snusnu/dm-accepts_nested_attributes
6
+
7
+ h3. Examples
8
+
9
+ The following example illustrates the use of this plugin.
10
+
11
+ <pre>
12
+ <code>
13
+ require "rubygems"
14
+
15
+ require "dm-core"
16
+ require "dm-validations"
17
+ require "dm-accepts_nested_attributes"
18
+
19
+ DataMapper::Logger.new(STDOUT, :debug)
20
+ DataMapper.setup(:default, 'sqlite3::memory:')
21
+
22
+ class Person
23
+ include DataMapper::Resource
24
+ property :id, Serial
25
+ property :name, String
26
+ has 1, :profile
27
+ has n, :project_memberships
28
+ has n, :projects, :through => :project_memberships
29
+
30
+ accepts_nested_attributes_for :profile
31
+ accepts_nested_attributes_for :projects
32
+
33
+ # adds the following instance methods
34
+ # #profile_attributes=
35
+ # #profile_attributes
36
+ # #projects_attributes=
37
+ # #projects_attributes
38
+ end
39
+
40
+ class Profile
41
+ include DataMapper::Resource
42
+ property :id, Serial
43
+ property :person_id, Integer
44
+ belongs_to :person
45
+
46
+ accepts_nested_attributes_for :person
47
+
48
+ # adds the following instance methods
49
+ # #person_attributes=
50
+ # #person_attributes
51
+ end
52
+
53
+ class Project
54
+ include DataMapper::Resource
55
+ property :id, Serial
56
+ has n, :tasks
57
+ has n, :project_memberships
58
+ has n, :people, :through => :project_memberships
59
+
60
+ accepts_nested_attributes_for :tasks
61
+ accepts_nested_attributes_for :people
62
+
63
+ # adds the following instance methods
64
+ # #tasks_attributes=
65
+ # #tasks_attributes
66
+ # #people_attributes=
67
+ # #people_attributes
68
+ end
69
+
70
+ class ProjectMembership
71
+ include DataMapper::Resource
72
+ property :id, Serial
73
+ property :person_id, Integer
74
+ property :project_id, Integer
75
+ belongs_to :person
76
+ belongs_to :project
77
+ end
78
+
79
+ class Task
80
+ include DataMapper::Resource
81
+ property :id, Serial
82
+ property :project_id, Integer
83
+ belongs_to :project
84
+ end
85
+
86
+ DataMapper.auto_migrate!
87
+ </code>
88
+ </pre>
89
+
90
+ h2. TODO
91
+
92
+ * collect validation errors from related resources
93
+ * update README to include more complete usecases
94
+ * think about replacing :reject_if with :if and :unless
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = 'dm-accepts_nested_attributes'
9
+ gem.summary = 'Nested model assignment for datamapper'
10
+ gem.description = 'A datamapper plugin that allows nested model assignment like activerecord.'
11
+ gem.email = 'gamsnjaga [a] gmail [d] com'
12
+ gem.homepage = 'http://github.com/snusnu/dm-accepts_nested_attributes'
13
+ gem.authors = [ 'Martin Gamsjaeger (snusnu)' ]
14
+ gem.has_rdoc = 'yard'
15
+ end
16
+
17
+ Jeweler::GemcutterTasks.new
18
+
19
+ FileList['tasks/**/*.rake'].each { |task| import task }
20
+
21
+ rescue LoadError => e
22
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
23
+ puts '-----------------------------------------------------------------------------'
24
+ puts e.backtrace # Let's help by actually showing *which* dependency is missing
25
+ end
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ TODO
2
+ ====
3
+
4
+ * collect validation errors from related resources
5
+ * update README to include more complete usecases
6
+ * think about replacing :reject_if with :if and :unless
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.0
@@ -0,0 +1,114 @@
1
+ 2# Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{dm-accepts_nested_attributes_for}
8
+ s.version = "1.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Martin Gamsjaeger (snusnu)}]
12
+ s.date = %q{2011-09-23}
13
+ s.description = %q{A datamapper plugin that allows nested model assignment like activerecord.}
14
+ s.email = %q{gamsnjaga [a] gmail [d] com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.textile",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ "CHANGELOG",
22
+ "Gemfile",
23
+ "LICENSE",
24
+ "README.textile",
25
+ "Rakefile",
26
+ "TODO",
27
+ "VERSION",
28
+ "dm-accepts_nested_attributes.gemspec",
29
+ "lib/dm-accepts_nested_attributes.rb",
30
+ "lib/dm-accepts_nested_attributes/model.rb",
31
+ "lib/dm-accepts_nested_attributes/relationship.rb",
32
+ "lib/dm-accepts_nested_attributes/resource.rb",
33
+ "lib/dm-accepts_nested_attributes/version.rb",
34
+ "spec/accepts_nested_attributes_for_spec.rb",
35
+ "spec/assign_nested_attributes_for_spec.rb",
36
+ "spec/comb/1-1_disjoint_spec.rb",
37
+ "spec/comb/1-1_overlapping_spec.rb",
38
+ "spec/comb/1-1_subset_spec.rb",
39
+ "spec/comb/1-1_superset_spec.rb",
40
+ "spec/comb/1-m_disjoint_spec.rb",
41
+ "spec/comb/1-m_overlapping_spec.rb",
42
+ "spec/comb/1-m_subset_spec.rb",
43
+ "spec/comb/1-m_superset_spec.rb",
44
+ "spec/comb/m-1_disjoint_spec.rb",
45
+ "spec/comb/m-1_overlapping_spec.rb",
46
+ "spec/comb/m-1_subset_spec.rb",
47
+ "spec/comb/m-1_superset_spec.rb",
48
+ "spec/comb/n-m_composite_spec.rb",
49
+ "spec/comb/n-m_surrogate_spec.rb",
50
+ "spec/many_to_many_composite_spec.rb",
51
+ "spec/many_to_many_spec.rb",
52
+ "spec/many_to_one_composite_spec.rb",
53
+ "spec/many_to_one_spec.rb",
54
+ "spec/one_to_many_composite_spec.rb",
55
+ "spec/one_to_many_spec.rb",
56
+ "spec/one_to_one_composite_spec.rb",
57
+ "spec/one_to_one_spec.rb",
58
+ "spec/rcov.opts",
59
+ "spec/resource_spec.rb",
60
+ "spec/shared/many_to_many_composite_spec.rb",
61
+ "spec/shared/many_to_many_spec.rb",
62
+ "spec/shared/many_to_one_composite_spec.rb",
63
+ "spec/shared/many_to_one_spec.rb",
64
+ "spec/shared/one_to_many_composite_spec.rb",
65
+ "spec/shared/one_to_many_spec.rb",
66
+ "spec/shared/one_to_one_composite_spec.rb",
67
+ "spec/shared/one_to_one_spec.rb",
68
+ "spec/spec.opts",
69
+ "spec/spec_helper.rb",
70
+ "spec/update_dirty_spec.rb",
71
+ "spec/update_multiple_spec.rb",
72
+ "tasks/changelog.rake",
73
+ "tasks/ci.rake",
74
+ "tasks/local_gemfile.rake",
75
+ "tasks/spec.rake",
76
+ "tasks/yard.rake",
77
+ "tasks/yardstick.rake"
78
+ ]
79
+ s.homepage = %q{http://github.com/snusnu/dm-accepts_nested_attributes}
80
+ s.require_paths = [%q{lib}]
81
+ s.rubygems_version = %q{1.8.5}
82
+ s.summary = %q{Nested model assignment for datamapper}
83
+
84
+ if s.respond_to? :specification_version then
85
+ s.specification_version = 3
86
+
87
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
88
+ s.add_runtime_dependency(%q<dm-core>, ["~> 1.2.0"])
89
+ s.add_development_dependency(%q<dm-validations>, ["~> 1.2.0"])
90
+ s.add_development_dependency(%q<dm-constraints>, ["~> 1.2.0"])
91
+ s.add_development_dependency(%q<rake>, ["~> 0.9.2"])
92
+ s.add_development_dependency(%q<rspec>, ["~> 1.3.2"])
93
+ s.add_development_dependency(%q<yard>, ["~> 0.7.2"])
94
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
95
+ else
96
+ s.add_dependency(%q<dm-core>, ["~> 1.2.0"])
97
+ s.add_dependency(%q<dm-validations>, ["~> 1.2.0"])
98
+ s.add_dependency(%q<dm-constraints>, ["~> 1.2.0"])
99
+ s.add_dependency(%q<rake>, ["~> 0.9.2"])
100
+ s.add_dependency(%q<rspec>, ["~> 1.3.2"])
101
+ s.add_dependency(%q<yard>, ["~> 0.7.2"])
102
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
103
+ end
104
+ else
105
+ s.add_dependency(%q<dm-core>, ["~> 1.2.0"])
106
+ s.add_dependency(%q<dm-validations>, ["~> 1.2.0"])
107
+ s.add_dependency(%q<dm-constraints>, ["~> 1.2.0"])
108
+ s.add_dependency(%q<rake>, ["~> 0.9.2"])
109
+ s.add_dependency(%q<rspec>, ["~> 1.3.2"])
110
+ s.add_dependency(%q<yard>, ["~> 0.7.2"])
111
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
112
+ end
113
+ end
114
+
@@ -0,0 +1,13 @@
1
+ require 'dm-core'
2
+
3
+ require 'dm-accepts_nested_attributes/model'
4
+ require 'dm-accepts_nested_attributes/resource'
5
+ require 'dm-accepts_nested_attributes/relationship'
6
+
7
+ # Activate the plugin
8
+ DataMapper::Model.append_extensions(DataMapper::NestedAttributes::Model)
9
+ DataMapper::Associations::Relationship.send(:include, DataMapper::NestedAttributes::Relationship)
10
+ DataMapper::Associations::ManyToMany::Relationship.send(:include, DataMapper::NestedAttributes::ManyToMany)
11
+ DataMapper::Associations::OneToMany::Relationship.send(:include, DataMapper::NestedAttributes::OneToMany)
12
+ DataMapper::Associations::ManyToOne::Relationship.send(:include, DataMapper::NestedAttributes::ManyToOne)
13
+ DataMapper::Associations::OneToOne::Relationship.send(:include, DataMapper::NestedAttributes::OneToOne)
@@ -0,0 +1,144 @@
1
+ module DataMapper
2
+ module NestedAttributes
3
+ class BackwardsCompatibilityHash < Hash
4
+ def initialize(model)
5
+ @model = model
6
+ end
7
+
8
+ def [](key)
9
+ if key.is_a?(DataMapper::Associations::Relationship)
10
+ warn "#{@model}#options_for_nested_attributes: Using a relationship " +
11
+ "as key is deprecated. Use the relationship name (i.e. " +
12
+ "#{key.name.inspect}) as key."
13
+ key = key.name
14
+ end
15
+ super(key)
16
+ end
17
+
18
+ def []=(key, value)
19
+ if key.is_a?(DataMapper::Associations::Relationship)
20
+ warn "#{@model}#options_for_nested_attributes: Using a relationship " +
21
+ "as key is deprecated. Use the relationship name (i.e. " +
22
+ "#{key.name.inspect}) as key."
23
+ key = key.name
24
+ end
25
+ super(key, value)
26
+ end
27
+ end
28
+
29
+ ##
30
+ # Named plugin exception that is raised by {Model#accepts_nested_attributes_for}
31
+ # if the passed options are invalid.
32
+ class InvalidOptions < ArgumentError; end
33
+
34
+ module Model
35
+
36
+ ##
37
+ # Allows an association to accept nested attributes.
38
+ #
39
+ # @param [Symbol, String] association_name
40
+ # The name of the association that should accept nested attributes.
41
+ #
42
+ # @param [Hash?] options
43
+ # List of resources to initialize the collection with.
44
+ #
45
+ # @option options [Symbol, String, #call] :reject_if
46
+ # An instance method name or an object that respond_to?(:call), which
47
+ # stops a new record from being created, if it evaluates to true.
48
+ #
49
+ # @option options [Boolean] :allow_destroy (false)
50
+ # If true, allows destroying the association via the generated writer.
51
+ # If false, prevents destroying the association via the generated writer.
52
+ #
53
+ # @raise [DataMapper::NestedAttributes::InvalidOptions]
54
+ # A named exception class indicating invalid options.
55
+ #
56
+ # @return [void]
57
+ #
58
+ def accepts_nested_attributes_for(association_name, options = {})
59
+
60
+ # ----------------------------------------------------------------------------------
61
+ # try to fail as early as possible
62
+ # ----------------------------------------------------------------------------------
63
+
64
+ unless relationship = relationships(repository_name)[association_name]
65
+ raise(ArgumentError, "No relationship #{association_name.inspect} for '#{name}' in :#{repository_name} repository")
66
+ end
67
+
68
+ # raise InvalidOptions if the given options don't make sense
69
+ assert_valid_options_for_nested_attributes(options)
70
+
71
+ # by default, nested attributes can't be destroyed
72
+ options = { :allow_destroy => false }.update(options)
73
+
74
+ # ----------------------------------------------------------------------------------
75
+ # should be safe to go from here
76
+ # ----------------------------------------------------------------------------------
77
+
78
+ options_for_nested_attributes[relationship.name] = options
79
+
80
+ include ::DataMapper::NestedAttributes::Resource
81
+
82
+ type = relationship.max > 1 ? :collection : :resource
83
+
84
+ define_method "#{association_name}_attributes" do
85
+ instance_variable_get("@#{association_name}_attributes")
86
+ end
87
+
88
+ define_method "#{association_name}_attributes=" do |attributes|
89
+ attributes = sanitize_nested_attributes(attributes)
90
+ instance_variable_set("@#{association_name}_attributes", attributes)
91
+ send("assign_nested_attributes_for_related_#{type}", relationship, attributes)
92
+ end
93
+
94
+ end
95
+
96
+ # Returns a hash with the options for all associations (using the
97
+ # corresponding relationship as key) that accept nested attributes.
98
+ #
99
+ # @return [Hash{DataMapper::Associations::Relationship => Hash}]
100
+ def options_for_nested_attributes
101
+ @options_for_nested_attributes ||= DataMapper::NestedAttributes::BackwardsCompatibilityHash.new(self)
102
+ end
103
+
104
+
105
+ private
106
+
107
+ ##
108
+ # Checks options passed to {#accepts_nested_attributes_for}.
109
+ # If any of the given options is invalid, this method will raise
110
+ # {DataMapper::NestedAttributes::InvalidOptions}.
111
+ #
112
+ # @param [Hash?] options
113
+ # The options passed to {#accepts_nested_attributes_for}.
114
+ #
115
+ # @raise [DataMapper::NestedAttributes::InvalidOptions]
116
+ # A named exception class indicating invalid options.
117
+ #
118
+ # @return [void]
119
+ #
120
+ def assert_valid_options_for_nested_attributes(options)
121
+
122
+ assert_kind_of 'options', options, Hash
123
+
124
+ valid_options = [ :allow_destroy, :reject_if ]
125
+
126
+ unless options.all? { |k,v| valid_options.include?(k) }
127
+ raise InvalidOptions, 'options must be one of :allow_destroy or :reject_if'
128
+ end
129
+
130
+ guard = options[:reject_if]
131
+ if guard.is_a?(Symbol) || guard.is_a?(String)
132
+ msg = ":reject_if => #{guard.inspect}, but there is no instance method #{guard.inspect} in #{self.name}"
133
+ raise InvalidOptions, msg unless instance_methods.include?(options[:reject_if].to_s)
134
+ else
135
+ msg = ":reject_if must be a Symbol|String or respond_to?(:call) "
136
+ raise InvalidOptions, msg unless guard.nil? || guard.respond_to?(:call)
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+
143
+ end
144
+ end