mood_swing 0.0.1
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.
- 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
|
+
|