acts-as-optionable 0.0.0 → 0.1.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 ADDED
@@ -0,0 +1,116 @@
1
+ = ActsAsOptionable
2
+
3
+ *Warning* I don't recommend using this yet since I'm going to make a couple core changes shortly. Very alpha.
4
+
5
+ Support to add options, as well as specify default options, to ActiveRecord models. It's currently a very basic approach, and allows you to fetch options from an ActiveRecord model via an association, or via a hash or object where options are callable as methods. It doesn't support any advanced finder options.
6
+
7
+ It works by creating an options table which is polymorphic to ActiveRecord models which call acts_as_optionable.
8
+
9
+ The plugin also grants the ability to specify default options for a class, or pass in defaults to an instance at runtime.
10
+
11
+ == Installation
12
+
13
+ Available as a gem:
14
+
15
+ gem install acts-as-optionable
16
+
17
+ === Post Installation
18
+
19
+ This creates an Option model in you app.
20
+
21
+ 1. script/generate option
22
+ 2. Rake db:migrate
23
+
24
+ == Usage
25
+
26
+ === Adding options to a model
27
+
28
+ class Style < ActiveRecord::Base
29
+ acts_as_optionable
30
+ end
31
+
32
+ === Setting, getting, and deleting options
33
+
34
+ Use #get_option, #set_option, and #delete_option for interacting with options.
35
+
36
+ style = Style.create
37
+ style.set_option("color", "red")
38
+ style.get_option("color").value => "red"
39
+ style.delete_option("color")
40
+ style.get_option("color") => nil
41
+
42
+
43
+ === Specifying default options at the class level
44
+
45
+ class StyleWithDefaults < ActiveRecord::Base
46
+ acts_as_optionable
47
+
48
+ specify_option :background_color, :default => "white"
49
+ specify_option :color, :default => "black"
50
+ end
51
+
52
+ style = StyleWithDefaults.create
53
+ style.get_option("background_color").value => "white"
54
+
55
+ === Specifying instance options at runtime
56
+
57
+ style.instance_specified_options = { :foo => {:default => "FOO"} }
58
+ style.get_option("foo").value => "FOO"
59
+
60
+ === Persisting options specific to a record
61
+
62
+ You can persist numeric, boolean, or string values for storage.
63
+
64
+ style.set_option("color", "red")
65
+ style.get_option("color").value => "red"
66
+
67
+ style.set_option("active", false)
68
+ style.get_option("active").value => false
69
+
70
+ style.set_option("max_time", 3600)
71
+ style.get_option("max_time").value => 3600
72
+
73
+ === Option precedence
74
+
75
+ Options are preferred in the following order:
76
+
77
+ 1. Stored options specific for this record
78
+ 2. Runtime options provided to the instance
79
+ 3. Class options specified at load time.
80
+
81
+ Example:
82
+
83
+ class StyleWithDefaults < ActiveRecord::Base
84
+ acts_as_optionable
85
+
86
+ specify_option :background_color, :default => "white"
87
+ specify_option :color, :default => "black"
88
+ end
89
+
90
+ style = StyleWithDefaults.create
91
+ style.instance_specified_options = { :color => { :default => "green" } }
92
+ style.get_option("background_color").value => "white"
93
+ style.get_option("color").value => "green"
94
+ style.set_option("color", "blue")
95
+ style.get_option("color").value => "blue"
96
+
97
+
98
+ === Easy options and values retrieval
99
+
100
+ Use #options_values_struct to grab a struct to allow for method based calls for all default and set options:
101
+
102
+ style = StyleWithDefaults.create
103
+ options = style.options_values_struct
104
+ options.color => "black"
105
+
106
+ This is useful, for instance, for passing a set of options into a liquid template.
107
+
108
+ == TODO
109
+
110
+ * Thinking about finding a way to optionally associate the option with an asset table. This would be useful for allowing user defined stylesheet options referencing S3 assets.
111
+ * Add in a way to return an option value straight away.
112
+ * Assign multiple settings at a time.
113
+
114
+
115
+
116
+ Copyright (c) 2010 Brendon Murphy, released under the MIT license
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.1.1
@@ -15,6 +15,7 @@ module ActiveRecord
15
15
  end
16
16
 
17
17
  module IntanceMethods
18
+ # Store an option persistently and override default option
18
19
  def set_option(name, value)
19
20
  option = get_stored_option(name) || options.build(:name => name.to_s)
20
21
  return if new_option_matches_current?(option)
@@ -24,19 +25,13 @@ module ActiveRecord
24
25
  ret
25
26
  end
26
27
 
28
+ # Get a stored option, or fall back to a default option
27
29
  def get_option(name)
28
30
  get_stored_option(name) ||
29
31
  get_default_option(name)
30
- end
31
-
32
- def get_default_option(name)
33
- instance_specified_option(name) || self.class.get_specified_option(name)
34
- end
35
-
36
- def get_default_options
37
- self.class.optionable_specified_options.merge(instance_specified_options || {})
38
- end
32
+ end
39
33
 
34
+ # Delete a stored option.
40
35
  def delete_option(name)
41
36
  if option = options(:reload).find_by_name(name.to_s)
42
37
  option = option.destroy
@@ -46,26 +41,53 @@ module ActiveRecord
46
41
  end
47
42
 
48
43
  def options_and_defaults
49
- options_as_hash = options.inject({}) do |memo, option|
50
- memo[option.name.to_s] = option
51
- memo
52
- end
53
44
  get_default_options.merge(options_as_hash)
54
45
  end
55
-
56
- def specified_options
57
- raise "TODO"
58
- end
59
46
 
47
+ # Returns an instance of options where option names are callable as methods
48
+ #
49
+ # Example:
50
+ # # Where foo is 'FOO' & bar is 'BAR'
51
+ # options = foo.options_values_struct
52
+ # options.foo => "FOO"
53
+ # options.bar => "BAR"
54
+ def options_values_struct
55
+ options = {}
56
+ options_and_defaults.each do |name, option|
57
+ options[name.to_s] = option.value
58
+ end
59
+ OpenStruct.new(options)
60
+ end
61
+
60
62
  protected
61
63
 
64
+ # Gets the default option if set. Prefers instance default over class default.
65
+ def get_default_option(name)
66
+ instance_specified_option(name) || self.class.get_specified_option(name)
67
+ end
68
+
69
+ # Get a hash of all default options, with option names as keys.
70
+ def get_default_options
71
+ self.class.optionable_specified_options.merge(instance_specified_options || {})
72
+ end
73
+
74
+ # Find the stored option in the database
62
75
  def get_stored_option(name)
63
76
  options.detect { |option| option.name.to_s == name.to_s }
64
77
  end
65
78
 
79
+ # Check if a new value provided is the same as the default option.
66
80
  def new_option_matches_current?(option)
67
81
  (!option.new_record? && option.value == value) || (get_default_option(name).value == value rescue nil)
68
82
  end
83
+
84
+ # Return the stored options as a hash, with the option names as keys.
85
+ def options_as_hash
86
+ options.inject({}) do |memo, option|
87
+ memo[option.name.to_s] = option
88
+ memo
89
+ end
90
+ end
69
91
  end
70
92
  end
71
93
  end
@@ -3,14 +3,17 @@ module ActiveRecord
3
3
  module Optionable
4
4
  module SpecifyOption
5
5
  module ClassMethods
6
+ # Setup a default value at the class level.
6
7
  def specify_option(option_name, opts = {})
7
8
  optionable_specified_options[option_name.to_s] = Option.new_readonly(:name => option_name.to_s, :default => opts[:default])
8
9
  end
9
10
 
11
+ # Returns a hash of options specified at the class level
10
12
  def optionable_specified_options
11
13
  @optionable_specified_options ||= {}
12
14
  end
13
15
 
16
+ # Get an option specified at the class level.
14
17
  def get_specified_option(option_name)
15
18
  optionable_specified_options[option_name.to_s]
16
19
  end
@@ -19,12 +22,20 @@ module ActiveRecord
19
22
  module InstanceMethods
20
23
  attr_reader :instance_specified_options
21
24
 
25
+ # Return an option specified for this instance
22
26
  def instance_specified_option(option_name)
23
27
  instance_specified_options[option_name.to_s] if instance_specified_options
24
28
  end
25
29
 
30
+ # Setup instance options. Pass in a hash of options as such:
31
+ # instance_options = {
32
+ # :foo => { :default => "FOO" },
33
+ # :bar => { :default => "BAR" }
34
+ # }
35
+ # foo.instance_specified_options = instance_options
36
+ #
37
+ # These options only persist in the instance, and aren't stored to database.
26
38
  def instance_specified_options=(opts)
27
- opts.symbolize_keys!
28
39
  @instance_specified_options = {}
29
40
  opts.each do |option_name, attributes|
30
41
  attributes.symbolize_keys!
@@ -63,7 +63,7 @@ describe "ActsAsOptionable" do
63
63
 
64
64
  describe "specifying options at class level" do
65
65
  it "should have the proper number of options set" do
66
- @optionable.get_default_options.length.should == 2
66
+ @optionable.options_and_defaults.keys.length.should == 2
67
67
  end
68
68
 
69
69
  it "should have the expected options set" do
@@ -229,4 +229,25 @@ describe "ActsAsOptionable" do
229
229
  end
230
230
  end
231
231
  end
232
+
233
+ describe "fetching an object with option names and values" do
234
+ it "should have a method to fetch option names and values" do
235
+ lambda { @optionable.options_values_struct }.should_not raise_error(NoMethodError)
236
+ end
237
+
238
+ it "should return an object that lets us retreive values by calling a method named for the option" do
239
+ option_values = @optionable.options_values_struct
240
+ option_values.foo.should == "FOOFOO"
241
+ option_values.bar.should == "BARBAR"
242
+ end
243
+
244
+ it "should contain both set and default options" do
245
+ @optionable.instance_specified_options = @options_template
246
+ @optionable.set_option("example_option", 99)
247
+ option_values = @optionable.options_values_struct
248
+ option_values.foo.should == "FOOFOO"
249
+ option_values.fizz.should == "FIZZFIZZ"
250
+ option_values.example_option.should == 99
251
+ end
252
+ end
232
253
  end
data/spec/spec.opts ADDED
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
5
+ --drb
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 0
8
- - 0
9
- version: 0.0.0
7
+ - 1
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brendon Murphy
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-22 00:00:00 -07:00
17
+ date: 2010-04-23 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -25,10 +25,10 @@ executables: []
25
25
  extensions: []
26
26
 
27
27
  extra_rdoc_files:
28
- - README
28
+ - README.rdoc
29
29
  files:
30
30
  - MIT-LICENSE
31
- - README
31
+ - README.rdoc
32
32
  - Rakefile
33
33
  - VERSION
34
34
  - lib/acts-as-optionable.rb
@@ -38,6 +38,7 @@ files:
38
38
  - lib/acts_as_optionable/specify_option.rb
39
39
  - rails/init.rb
40
40
  - spec/acts_as_optionable_spec.rb
41
+ - spec/spec.opts
41
42
  - spec/spec_helper.rb
42
43
  has_rdoc: true
43
44
  homepage: http://github.com/bemurphy/acts_as_optionable
data/README DELETED
@@ -1,13 +0,0 @@
1
- ActsAsOptionable
2
- ================
3
-
4
- I don't recommend using this yet since I'm going to make a couple core changes shortly. Very alpha.
5
-
6
-
7
- Example
8
- =======
9
-
10
- Example goes here.
11
-
12
-
13
- Copyright (c) 2010 [name of plugin creator], released under the MIT license