mood_swing 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,36 @@
1
+ = Mood Swing
2
+
3
+ As we've been taught, conditional statements can be a code smell and a good way to clean them up is polymorphism. I've
4
+ found that with rails coupling the persistence layer and the business logic sometimes the standard form of inheritance-
5
+ based polymorphism is awkward or not feasible. However, Ruby with it's dynamic object model can provide a form of
6
+ inheritance via extending instances by mixing in modules dynamically. Mood Swing embraces this and provides a convenient
7
+ means of doing it.
8
+
9
+ == Usage
10
+
11
+ You simply define the class macro mood_trigger and pass it the attribute in which will be used to load the module. The
12
+ value of the attribute will be inflected with .classify and then a module matching "#{value}Extension" will be loaded if
13
+ it is available with in the class namespace. Given the mood_trigger attribute is breed, with a value of hound, in the
14
+ class named Dog, then the module would be named Dog::HoundExtension.
15
+
16
+ class Dog < ActiveRecord::Base
17
+ mood_trigger 'breed'
18
+
19
+ def bark
20
+ 'woof'
21
+ end
22
+
23
+ module HoundExtension
24
+ def bark
25
+ 'Hoooooowl'
26
+ end
27
+ end
28
+ end
29
+
30
+ Now whenever you load a dog with the breed set to hound, or if you assign the breed to hound, it will bark out "Hoooooowl"
31
+
32
+ Optionally, you can supply a writer attribute if the writer is not the same as the reader. This is the case with with
33
+ polymorphic associations.
34
+
35
+ belongs_to 'body', :polymorphic => true
36
+ mood_trigger 'body_type', :writer => 'body'
@@ -0,0 +1,68 @@
1
+ # Allows polymorphic behavior based on the value of an attribute by including a module dynamically.
2
+ module MoodSwing
3
+
4
+ # reader is the value to use as the basis of the included module. The convention for naming the include is:
5
+ # YourClass::YourNameExtension
6
+ #
7
+ # An example would be:
8
+ #
9
+ # class Dog < ActiveRecord::Base
10
+ # mood_trigger 'breed'
11
+ #
12
+ # def bark
13
+ # puts 'woof'
14
+ # end
15
+ # end
16
+ #
17
+ # module Dog::HoundExtension
18
+ # def bark
19
+ # puts 'Hoooooowl'
20
+ # end
21
+ # end
22
+ #
23
+ # When a instance of dog is initialized the breed attribute is read and it's value is used to extend the current
24
+ # instance's behavior with the module matching following the previously mentioned convention. If the Dog instance's
25
+ # breed was "Hound" then it would be extended with the Dog::HoundExtension. Now when you call @dog.bark, your dog will
26
+ # howl instead of woof.
27
+ #
28
+ # The module is updated when the attribute changes. An example of the behavior to expect with a new object is:
29
+ #
30
+ # spot = Dog.new
31
+ # spot.bark
32
+ # => "woof"
33
+ # spot.breed = "hound"
34
+ # spot.bark
35
+ # => 'Hoooooowl'
36
+ #
37
+ # If your attribute writer is different from the reader, then you can pass in :writer => "your_writer_method" and it
38
+ # will use that. This is the case when using a polymorphic belongs_to accessor as the attribute.
39
+ #
40
+ # belongs_to 'body', :polymorphic => true
41
+ # mood_trigger 'body_type', :writer => 'body'
42
+ def mood_trigger(reader, options ={})
43
+ options[:writer] ||= reader
44
+
45
+ define_method("#{options[:writer]}_with_extension=") do |value|
46
+ self.send "#{options[:writer]}_without_extension=", value
47
+ self.send "#{reader}_extension!"
48
+ self.send reader
49
+ end
50
+
51
+ define_method("#{reader}_extension!") do
52
+ begin
53
+ self.extend "#{self.class}::#{self[reader].classify}Extension".constantize
54
+ rescue NameError
55
+ end
56
+ end
57
+
58
+ class_eval do
59
+ alias_method_chain "#{options[:writer]}=", 'extension'
60
+ after_initialize "#{reader}_extension!"
61
+ end
62
+ end
63
+ end
64
+
65
+ ActiveSupport.on_load(:active_record) do
66
+ extend MoodSwing
67
+ end
68
+
@@ -0,0 +1,3 @@
1
+ module MoodSwing
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mood_swing
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - TJ Singleton
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-23 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Allows polymorphic behavior based on the value of an attribute by including a module dynamically.
23
+ email: tjsingleton@vantagestreet.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/mood_swing/version.rb
32
+ - lib/mood_swing.rb
33
+ - README.rdoc
34
+ has_rdoc: true
35
+ homepage: http://github.com/tjsingleton/mood_swing
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ hash: 3
49
+ segments:
50
+ - 0
51
+ version: "0"
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.7
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Polymorphic behavior based on the value of an attribute
68
+ test_files: []
69
+