has_many_callbacks 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4702d26c8756bc050e4acf0daba8e4db79999678
4
+ data.tar.gz: 8422e002a2bc0a4aab26e7187b57a2acf5d08521
5
+ SHA512:
6
+ metadata.gz: fe3d05719cd28020ad81c4b9754f8aa372065e5ce233464703940ffb399cfffbb8995c4047a8867d7566e42f85829fb226492145f4cb41a819fcccd99ecedf4e
7
+ data.tar.gz: 86afc2005b6cb85c0dcbc67db0c7ecadac108ba51ea2a4da17b5790b8f95cddd7291436df6df579813a46373db1133d7791e72c824c3e402a404f2083cc2f7ae
@@ -0,0 +1,20 @@
1
+ Copyright 2013 Jose Fernandes
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,43 @@
1
+ = has_many_callbacks
2
+ Adds additional callback hooks to ActiveRecord has_many relations.
3
+
4
+ === Motivation
5
+ Callback hooks are a common pattern in software development, used when modeling event driven
6
+ behavior.
7
+
8
+ Rails has_many relations provide hooks to child events, but they have several shortcomings. This
9
+ gem provides additional callbacks, that are built on ActiveRecord model callbacks and work
10
+ in the same way.
11
+
12
+ The main goal is ensuring the code that expresses the relation parent behavior when handling events
13
+ triggered by child objects is kept in the parent code base, where it belongs. If the parent
14
+ has a lot of relations, this prevents that class' code to be scattered accross all the child
15
+ class definitions.
16
+
17
+ === Example
18
+ Consider the following classes:
19
+
20
+ class TodoList
21
+ # name, completed
22
+ has_many :tasks
23
+ end
24
+
25
+ class Task
26
+ # name, completed
27
+ belongs_to :todo_list
28
+ end
29
+
30
+ Imagine that a To-Do list is completed if it's not empty and all the tasks in it get are completed.
31
+
32
+ class TodoList
33
+ has_many :tasks,
34
+ :after_save => lambda { |todo_list, task|
35
+ todo_list.completed = !task.completed ? false : todo_list.tasks.map(&:completed).inject(&:&)
36
+ todo_list.save! if todo_list.completed_changed?
37
+ }
38
+
39
+ end
40
+
41
+
42
+ === License
43
+ This software is provided under the MIT License. See MIT-LICENSE for details.
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'HasManyCallbacks'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
@@ -0,0 +1,66 @@
1
+
2
+ module HasManyCallbacks
3
+ extend ActiveSupport::Concern
4
+
5
+ class HasManyWithChildCallbacksBuilder < ActiveRecord::Associations::Builder::HasMany
6
+ HAS_MANY_CALLBACKS = [ :after_create, :after_save, :after_destroy ]
7
+ def valid_options
8
+ super + HAS_MANY_CALLBACKS
9
+ end
10
+
11
+ def build
12
+ association = super
13
+
14
+ hook_callback = lambda do |callback_name|
15
+ callback_option = association.options[callback_name]
16
+
17
+ if callback_option.is_a?(Symbol)
18
+ callback_code = "target.send(:#{callback_option}, obj)"
19
+ else
20
+ callback_code = "callback_option[target, obj]"
21
+ end
22
+
23
+ if association.inverse_of.macro == :has_many
24
+ target_callback_iteration_code = "associated_obj.each { |target| #{callback_code} }"
25
+ else
26
+ target_callback_iteration_code = "target = associated_obj; #{callback_code}"
27
+ end
28
+
29
+ code = %{
30
+ #{callback_name} do |obj|
31
+ association = obj.class.reflect_on_association(:#{association.inverse_of.name})
32
+ inverse_association = association.klass.reflect_on_association(:#{association.name})
33
+ callback_option = inverse_association.options[:#{callback_name}]
34
+ associated_obj = obj.send(association.name)
35
+
36
+ if associated_obj.present?
37
+ #{target_callback_iteration_code}
38
+ end
39
+ end
40
+ }
41
+ association.klass.instance_eval code
42
+ end
43
+
44
+ HAS_MANY_CALLBACKS.each do |callback|
45
+ if options[callback].present?
46
+ hook_callback[callback]
47
+ #puts "#{model.to_s}: hooking #{callback} on #{association.try(:name)}"
48
+ end
49
+ end
50
+
51
+
52
+ #hook_callback.call(:after_create, after_create_callback) if after_create_callback.present?
53
+ association
54
+ end
55
+ end
56
+
57
+ module ClassMethods
58
+ def has_many(name, scope = nil, options = {}, &extension)
59
+ HasManyWithChildCallbacksBuilder.build(self, name, scope, options, &extension)
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ ActiveRecord::Base.send(:include, HasManyCallbacks)
66
+ ActiveRecord::Base.send(:include, HasManyCallbacks::ClassMethods)
@@ -0,0 +1,3 @@
1
+ module HasManyCallbacks
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :has_many_callbacks do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_many_callbacks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Jose Fernandes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: spork-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: factory_girl_rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: database_cleaner
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: No additional description yet.
98
+ email:
99
+ - jpcfernandes@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - lib/has_many_callbacks/version.rb
105
+ - lib/has_many_callbacks.rb
106
+ - lib/tasks/has_many_callbacks_tasks.rake
107
+ - MIT-LICENSE
108
+ - Rakefile
109
+ - README.rdoc
110
+ homepage: https://github.com/jpcfernandes
111
+ licenses:
112
+ - MIT-LICENSE
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project:
130
+ rubygems_version: 2.0.6
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Adds child callback options to has_many relations.
134
+ test_files: []