preference_fu 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use 1.9.2@preference_fu
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+ source 'http://gems.github.com'
3
+
4
+ gem 'jeweler','~>1.5'
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ remote: http://gems.github.com/
4
+ specs:
5
+ git (1.2.5)
6
+ jeweler (1.5.1)
7
+ bundler (~> 1.0.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rake (0.8.7)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ jeweler (~> 1.5)
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
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.
data/README ADDED
@@ -0,0 +1,76 @@
1
+ PreferenceFu
2
+ ============
3
+
4
+ This plugin, greatly inspired by Jim Morris' blog post (http://blog.wolfman.com/articles/2007/08/07/bit-vector-preferences), aims to make it easy and flexible to store boolean preferences for an ActiveRecord model. This can be also used as a very quick way to setup an ACL.
5
+
6
+ Because the values are stored within a bit vector, a virtually unlimited number of preferences can be created without additional migrations.
7
+
8
+ Feel free to email me with any suggestions or problems.
9
+
10
+ Blog: http://www.brennandunn.com
11
+ Email address: me@brennandunn.com
12
+
13
+
14
+ Setup
15
+ =====
16
+
17
+ Simply add an integer column to each table of the database that requires preferences. By default, the column used is 'preferences', and can be changed using an options hash when defining preferences:
18
+
19
+ has_preferences :send_email, :column => 'something_else'
20
+
21
+ Your migration should probably look something like this:
22
+
23
+ add_column :people, :preferences, :integer
24
+
25
+
26
+ Examples
27
+ ========
28
+
29
+ Using PreferenceFu is very simple.
30
+
31
+ class User < ActiveRecord::Base
32
+
33
+ has_preferences :send_email, :change_theme, :delete_user, :create_user
34
+
35
+ set_default_preference :send_email, true
36
+
37
+ end
38
+
39
+ For new AR objects, all preference options will be set to false. This can be overwritten using set_default_preference. I really recommend you read the 'Warning' section below.
40
+
41
+ Setting a key:
42
+ ...individually
43
+ @user.prefs[:delete_user] = true
44
+
45
+ ...mass assignment (useful with the params hash)
46
+ @user.prefs = {:delete_user => true, :create_user => true}
47
+
48
+ Setting an option as true doesn't necessarily need to be done with the Boolean true - in fact, the Fixnum 1, and strings '1', 'y' and 'yes' are all valid. This is particularly helpful for checkbox form posts.
49
+
50
+ @user.prefs[:create_user] = 'yes'
51
+
52
+
53
+ Fetching a key:
54
+ @user.prefs[:change_theme] => false
55
+
56
+
57
+ Getting the index of a key:
58
+ @user.prefs.index(:delete_user) => 4
59
+
60
+
61
+ Enumerable...
62
+ @user.prefs.size => 4
63
+
64
+ @user.prefs.each do |key, value|
65
+ puts "#{key} is set to #{value}"
66
+ end
67
+
68
+
69
+ Warning
70
+ =======
71
+
72
+ This works by taking the index of the splat supplied in has_preferences as the power of two, summing all values, and storing the sum in the preferences column. Because of this, the first item in the splat will be identified by 1, the second by 2, the third by 4, etc. Once you start using PreferenceFu in production, add new options to the *end* of the splat. At the moment, there's no safe way to delete a preference item at the moment. Any advice is welcome!
73
+
74
+
75
+
76
+ Copyright (c) 2008 Brennan Dunn, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rubygems'
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ require 'rake'
9
+ require 'rake/testtask'
10
+ require 'rake/rdoctask'
11
+
12
+ desc 'Default: run unit tests.'
13
+ task :default => :test
14
+
15
+ desc 'Test the preference_fu plugin.'
16
+ Rake::TestTask.new(:test) do |t|
17
+ t.libs << 'lib'
18
+ t.pattern = 'test/**/*_test.rb'
19
+ t.verbose = true
20
+ end
21
+
22
+ desc 'Generate documentation for the preference_fu plugin.'
23
+ Rake::RDocTask.new(:rdoc) do |rdoc|
24
+ rdoc.rdoc_dir = 'rdoc'
25
+ rdoc.title = 'PreferenceFu'
26
+ rdoc.options << '--line-numbers' << '--inline-source'
27
+ rdoc.rdoc_files.include('README')
28
+ rdoc.rdoc_files.include('lib/**/*.rb')
29
+ end
30
+
31
+ require 'jeweler'
32
+ Jeweler::Tasks.new do |gem|
33
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
34
+ gem.name = "preference_fu"
35
+ gem.summary = %Q{Rails 3 compatible plugin gem for boolean preferences for an ActiveRecord model}
36
+ gem.description = %Q{This plugin, greatly inspired by Jim Morris' blog post (http://blog.wolfman.com/articles/2007/08/07/bit-vector-preferences), aims to make it easy and flexible to store boolean preferences for an ActiveRecord model.This can be also used as a very quick way to setup an ACL. Because the values are stored within a bit vector, a virtually unlimited number of preferences can be created without additional migrations.}
37
+ gem.email = ""
38
+ gem.homepage = "http://github.com/g5search/preference_fu"
39
+ gem.authors = ["Brennan Dunn"]
40
+ gem.has_rdoc=true
41
+ end
42
+ Jeweler::GemcutterTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ # Include hook code here
2
+
3
+ ActiveRecord::Base.class_eval { include PreferenceFu }
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,158 @@
1
+ module PreferenceFu
2
+
3
+ def self.included(receiver)
4
+ receiver.extend ClassMethods
5
+ receiver.send :include, InstanceMethods
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ def has_preferences(*prefs)
11
+ alias_method_chain :initialize, :preferences
12
+
13
+ class_eval do
14
+ class << self
15
+ alias_method_chain :instantiate, :preferences
16
+ attr_accessor :preference_options
17
+ end
18
+ end
19
+
20
+ options = prefs.extract_options!
21
+ @config = { :column => 'preferences' }.merge(options)
22
+
23
+ self.preference_options = {}
24
+ prefs.each_with_index do |pref, idx|
25
+ self.preference_options[2**idx] = { :key => pref.to_sym, :default => false }
26
+ end
27
+
28
+ class << self
29
+ define_method(:preferences_column) { @config[:column] }
30
+ end
31
+
32
+ end
33
+
34
+ def set_default_preference(key, default)
35
+ raise ArgumentError.new("Default value must be boolean") unless [true, false].include?(default)
36
+ idx = preference_options.find { |idx, hsh| hsh[:key] == key.to_sym }.first rescue nil
37
+ if idx
38
+ preference_options[idx][:default] = default
39
+ end
40
+ end
41
+
42
+ def instantiate_with_preferences(*args)
43
+ record = instantiate_without_preferences(*args)
44
+ record.prefs
45
+ record
46
+ end
47
+
48
+ end
49
+
50
+ module InstanceMethods
51
+
52
+ def initialize_with_preferences(attributes = nil)
53
+ initialize_without_preferences(attributes)
54
+ prefs # use this to trigger update_permissions in Preferences
55
+ yield self if block_given?
56
+ end
57
+
58
+ def preferences_column
59
+ self.class.preferences_column
60
+ end
61
+
62
+ def prefs
63
+ @preferences_object ||= Preferences.new(read_attribute(preferences_column.to_sym), self)
64
+ end
65
+
66
+ def prefs=(hsh)
67
+ prefs.store(hsh)
68
+ end
69
+
70
+ end
71
+
72
+
73
+ class Preferences
74
+
75
+ include Enumerable
76
+
77
+ attr_accessor :instance, :options
78
+
79
+ def initialize(prefs, instance)
80
+ @instance = instance
81
+ @options = instance.class.preference_options
82
+
83
+ # setup defaults if prefs is nil
84
+ if prefs.nil?
85
+ @options.each do |idx, hsh|
86
+ instance_variable_set("@#{hsh[:key]}", hsh[:default])
87
+ end
88
+ elsif prefs.is_a?(Numeric)
89
+ @options.each do |idx, hsh|
90
+ instance_variable_set("@#{hsh[:key]}", (prefs & idx) != 0 ? true : false)
91
+ end
92
+ else
93
+ raise(ArgumentError, "Input must be numeric")
94
+ end
95
+
96
+ update_permissions
97
+
98
+ end
99
+
100
+ def each
101
+ @options.each_value do |hsh|
102
+ yield hsh[:key], self[hsh[:key]]
103
+ end
104
+ end
105
+
106
+ def size
107
+ @options.size
108
+ end
109
+
110
+ def [](key)
111
+ instance_variable_get("@#{key}")
112
+ end
113
+
114
+ def []=(key, value)
115
+ idx, hsh = lookup(key)
116
+ instance_variable_set("@#{key}", is_true(value))
117
+ update_permissions
118
+ end
119
+
120
+ def index(key)
121
+ idx, hsh = lookup(key)
122
+ idx
123
+ end
124
+
125
+ # used for mass assignment of preferences, such as a hash from params
126
+ def store(prefs)
127
+ prefs.each do |key, value|
128
+ self[key] = value
129
+ end if prefs.respond_to?(:each)
130
+ end
131
+
132
+ def to_i
133
+ @options.inject(0) do |bv, (idx, hsh)|
134
+ bv |= instance_variable_get("@#{hsh[:key]}") ? idx : 0
135
+ end
136
+ end
137
+
138
+ private
139
+
140
+ def update_permissions
141
+ instance.write_attribute(instance.preferences_column, self.to_i)
142
+ end
143
+
144
+ def is_true(value)
145
+ case value
146
+ when true, 1, /1|y|yes/i then true
147
+ else false
148
+ end
149
+ end
150
+
151
+ def lookup(key)
152
+ @options.find { |idx, hsh| hsh[:key] == key.to_sym }
153
+ end
154
+
155
+ end
156
+
157
+ end
158
+ ActiveRecord::Base.class_eval { include PreferenceFu }
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{preference_fu}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Brennan Dunn"]
12
+ s.date = %q{2010-11-15}
13
+ s.description = %q{This plugin, greatly inspired by Jim Morris' blog post (http://blog.wolfman.com/articles/2007/08/07/bit-vector-preferences), aims to make it easy and flexible to store boolean preferences for an ActiveRecord model.This can be also used as a very quick way to setup an ACL. Because the values are stored within a bit vector, a virtually unlimited number of preferences can be created without additional migrations.}
14
+ s.email = %q{}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ ".rvmrc",
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "MIT-LICENSE",
23
+ "README",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "init.rb",
27
+ "install.rb",
28
+ "lib/preference_fu.rb",
29
+ "preference_fu.gemspec",
30
+ "tasks/preference_fu_tasks.rake",
31
+ "test/abstract_unit.rb",
32
+ "test/person.rb",
33
+ "test/preference_fu_test.rb",
34
+ "uninstall.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/g5search/preference_fu}
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.7}
39
+ s.summary = %q{Rails 3 compatible plugin gem for boolean preferences for an ActiveRecord model}
40
+ s.test_files = [
41
+ "test/abstract_unit.rb",
42
+ "test/person.rb",
43
+ "test/preference_fu_test.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<jeweler>, ["~> 1.5"])
52
+ else
53
+ s.add_dependency(%q<jeweler>, ["~> 1.5"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<jeweler>, ["~> 1.5"])
57
+ end
58
+ end
59
+
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :preference_fu do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,27 @@
1
+ begin
2
+ require File.dirname(__FILE__) + '/../../../../config/environment'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'active_record'
6
+ gem 'activerecord'
7
+ end
8
+
9
+ require 'preference_fu'
10
+ require "#{File.dirname(__FILE__)}/../init"
11
+
12
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
13
+
14
+ def setup_db
15
+ ActiveRecord::Schema.define(:version => 1) do
16
+ create_table :people do |t|
17
+ t.string :name
18
+ t.integer :preferences
19
+ end
20
+ end
21
+ end
22
+
23
+ def teardown_db
24
+ ActiveRecord::Base.connection.tables.each do |table|
25
+ ActiveRecord::Base.connection.drop_table(table)
26
+ end
27
+ end
data/test/person.rb ADDED
@@ -0,0 +1,8 @@
1
+
2
+ class Person < ActiveRecord::Base
3
+
4
+ has_preferences :send_email, :change_theme, :delete_user, :create_user
5
+
6
+ set_default_preference :send_email, true
7
+
8
+ end
@@ -0,0 +1,65 @@
1
+ require 'test/unit'
2
+ require File.join(File.dirname(__FILE__), 'abstract_unit')
3
+ require File.join(File.dirname(__FILE__), 'person')
4
+
5
+
6
+ class PreferenceFuTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+ setup_db
10
+ @person = Person.new
11
+ end
12
+
13
+ def teardown
14
+ teardown_db
15
+ end
16
+
17
+ def test_that_all_default_to_true_except_send_email
18
+ assert_equal [true, false, false, false], @person.prefs.map { |k, v| v }
19
+ end
20
+
21
+ def test_new_user_for_default_preference_int
22
+ assert_equal 1, @person.read_attribute(:preferences)
23
+ end
24
+
25
+ def test_changing_the_default_preference_column
26
+ klass = Class.new(ActiveRecord::Base) { include PreferenceFu ; has_preferences :foo, :column => 'something_else' }
27
+ assert_equal 'something_else', klass.preferences_column
28
+ end
29
+
30
+ def test_changing_of_preference
31
+ assert_equal false, @person.prefs[:delete_user]
32
+ @person.prefs[:delete_user] = true
33
+ assert_equal true, @person.prefs[:delete_user]
34
+ end
35
+
36
+ def test_mass_assignment
37
+ @person.prefs = {:send_email => true, :change_theme => true, :delete_user => true, :create_user => true}
38
+ assert_equal [true, true, true, true], @person.prefs.map { |k, v| v }
39
+ end
40
+
41
+ def test_setting_an_unknown_option
42
+ @person.prefs[:unknown] = true
43
+ assert_equal 4, @person.prefs.size
44
+ end
45
+
46
+ def test_saving_and_loading
47
+ @person.prefs[:change_theme] = true
48
+ @person.save
49
+
50
+ @new_person = Person.find(:first)
51
+ assert_equal [true, true, false, false], @new_person.prefs.map { |k, v| v }
52
+ end
53
+
54
+ def test_various_ways_of_stating_truth
55
+ [true, 1, '1', 'y', 'yes', 'Y', 'YES'].each do |val|
56
+ @person.prefs[:change_theme] = val
57
+ assert_equal true, @person.prefs[:change_theme]
58
+ end
59
+ end
60
+
61
+ def test_lookup_index_of_key
62
+ assert_equal 4, @person.prefs.index(:delete_user)
63
+ end
64
+
65
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: preference_fu
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Brennan Dunn
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-15 00:00:00 -08:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: jeweler
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 5
30
+ version: "1.5"
31
+ type: :runtime
32
+ prerelease: false
33
+ version_requirements: *id001
34
+ description: This plugin, greatly inspired by Jim Morris' blog post (http://blog.wolfman.com/articles/2007/08/07/bit-vector-preferences), aims to make it easy and flexible to store boolean preferences for an ActiveRecord model.This can be also used as a very quick way to setup an ACL. Because the values are stored within a bit vector, a virtually unlimited number of preferences can be created without additional migrations.
35
+ email: ""
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README
42
+ files:
43
+ - .rvmrc
44
+ - Gemfile
45
+ - Gemfile.lock
46
+ - MIT-LICENSE
47
+ - README
48
+ - Rakefile
49
+ - VERSION
50
+ - init.rb
51
+ - install.rb
52
+ - lib/preference_fu.rb
53
+ - preference_fu.gemspec
54
+ - tasks/preference_fu_tasks.rake
55
+ - test/abstract_unit.rb
56
+ - test/person.rb
57
+ - test/preference_fu_test.rb
58
+ - uninstall.rb
59
+ has_rdoc: true
60
+ homepage: http://github.com/g5search/preference_fu
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: -1418568282675616323
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.7
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Rails 3 compatible plugin gem for boolean preferences for an ActiveRecord model
92
+ test_files:
93
+ - test/abstract_unit.rb
94
+ - test/person.rb
95
+ - test/preference_fu_test.rb