mood_swing 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +36 -0
- data/lib/mood_swing.rb +68 -0
- data/lib/mood_swing/version.rb +3 -0
- metadata +69 -0
data/README.rdoc
ADDED
@@ -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'
|
data/lib/mood_swing.rb
ADDED
@@ -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
|
+
|
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
|
+
|