has_setting 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,78 +1,72 @@
1
- ==What is it?
1
+ (This is now the official repository for the Simplificator [has_setting gem](https://github.com/simplificator/has_setting))
2
+
3
+ # What is it?
4
+
2
5
  has_setting is a simple extension that enables ActiveRecord models to
3
- store settings in a separate settings table as key/value pairs where the key and value are stored as Strings.
6
+ store settings in a separate settings table as key/value pairs where the key and value are stored as strings.
4
7
 
5
- ==History
6
- * 0.4.3:
7
- * Changed behaviour of :boolean formatters: Now they treat '0', 0, false, nil and '' as false, everything else as true
8
- This is not the same behaviour as ruby (treating only nil and false as false) but should help with input from web forms (i.e. checkboxes)
9
- If you want strict ruby boolean behaviour, then use :strict_boolean as :type
10
- * 0.4.2:
11
- * bug fixes for boolean types default values
12
- * 0.3.10:
13
- * added boolean and booleans formatters
14
- * 0.3.9:
15
- * added type :strings, :floats, :ints. They store the contents of an array as a comma separated string.
16
- * 0.3.8:
17
- * added dependent destroy option. no more zombie settings lingering around.
18
- * 0.3.7:
19
- * Gem is now built using jeweler... after messing around and bumping versions and getting
20
- strange errors, this is 'it works' feeling coming back
21
- * 0.3.4:
22
- * Added custom formatter support. no new formatters though...
23
- * 0.3.1:
24
- * Bug Fixed: has_many(:settings) is not added to ActiveRecord::Base but only to the classes with has_setting
25
- * Bug Fixed: options are not shared between classes
26
- * Again changed the way settings are saved. Save is now done on parent.save with an after_save callback. (like this the settings are treated as if they were attributes of the owner)
27
- * 0.2.x:
28
- * Added :default option
29
- * changed way settings are saved so that unsaved parents can have settings too
30
- * changed nameing scheme of setting names (incompatible with versions prior 0.2.x but since nobody uses the gem i dont care :-))
31
- * 0.1.x: First Version
32
8
 
9
+ # Installation
10
+
11
+ Add has_setting to your gemfile:
33
12
 
34
- ==Installation
35
- sudo gem install simplificator-has_setting
13
+ gem 'has_setting'
14
+
15
+ # Setup
36
16
 
37
- ==Setup
38
17
  * Add a migration that looks more or less like the one in <em>help/001_create_settings.rb</em>
39
18
  * Make sure the gem is loaded when your application starts
40
19
 
41
- ==Config
20
+ # Config
21
+
42
22
  The model you want to hold settings (i.e. User, Profile, ...):
43
- <tt>has_setting(:name_of_the_setting)</tt>
23
+
24
+ has_setting(:name_of_the_setting)
25
+
44
26
  This will create the following methods for you on the owner class:
45
- * <tt>name_of_the_setting=(value)</tt> a standard setter
46
- * <tt>name_of_the_setting()</tt> a standard getter (the getter method takes an optional hash to override some options, possible values are the same as the options in has_setting())
27
+ * `name_of_the_setting=(value)` a standard setter
28
+ * `name_of_the_setting()` a standard getter (the getter method takes an optional hash to override some options, possible values are the same as the options in has_setting())
47
29
 
48
- <tt>has_setting(name, options)</tt> takes an optional hash of options. Following options are supported:
49
- <em>:type</em> allows you to convert the value:
50
- * <em>:string</em> (default) Uses the StringFormatter to convert from/to String (actually this formatter just leaves the value as it is)
51
- * <em>:int</em> Uses the IntFormatter to convert from/to int values.
52
- * <em>:boolean</em> Uses the BooleanFormatter to convert from/to boolean values; treating 0, '0', false, '' and nil as false.
53
- * <em>:strict_boolean</em> Uses the StrictBooleanFormatter to convert from/to boolean values; treating false, and nil as false.
54
- * <em>:float</em> Uses the FloatFormatter to convert from/to float values.
55
- * <em>:ints</em> Uses the IntsFormatter to convert from/to int[]
56
- * <em>:floats</em> Uses the FloatsFormatter to convert from/to float[]
57
- * <em>:strings</em> Uses the StringsFormatter to convert from/to string[]
58
- * <em>:booleans</em> Uses the BooleansFormatter to convert from/to boolean[]
59
- * <em>:strict_booleans</em> Uses the BooleansFormatter to convert from/to boolean[]
60
- <em>:default</em> allows you to specify a default value that will be returned if the setting does not exist (i.e. has never been written). Note that the default value is _ignored_ if the setting exists, no matter what the value of the setting is. The default value is returned as is, no type conversion takes place.
61
-
62
-
63
-
64
- ==How it works
30
+ `has_setting(name, options)` takes an optional hash of options. Following options are supported:
31
+
32
+ *:type* allows you to convert the value:
33
+
34
+ * *:string* (default) Uses the StringFormatter to convert from/to String (actually this formatter just leaves the value as it is)
35
+ * *:int* Uses the IntFormatter to convert from/to int values.
36
+ * *:boolean* Uses the BooleanFormatter to convert from/to boolean values; treating 0, '0', false, '' and nil as false.
37
+ * *:strict_boolean* Uses the StrictBooleanFormatter to convert from/to boolean values; treating false, and nil as false.
38
+ * *:float* Uses the FloatFormatter to convert from/to float values.
39
+ * *:ints* Uses the IntsFormatter to convert from/to int[]
40
+ * *:floats* Uses the FloatsFormatter to convert from/to float[]
41
+ * *:strings* Uses the StringsFormatter to convert from/to string[]
42
+ * *:booleans* Uses the BooleansFormatter to convert from/to boolean[]
43
+ * *:strict_booleans* Uses the BooleansFormatter to convert from/to boolean[]
44
+ * *:default* allows you to specify a default value that will be returned if the setting does not exist (i.e. has never been written). Note that the default value is _ignored_ if the setting exists, no matter what the value of the setting is. The default value is returned as is, no type conversion takes place.
45
+
46
+
47
+
48
+ # How it works
49
+
65
50
  A polymorphic parent-child relation is created between Setting and the parent/owning class.
66
51
  Getters/setters are added through meta-programming-magic. If the setter is invoked on a unsafed parent then the setting is not saved until the parent is saved, else setting is saved upon creation (i.e. first time the setter is called) / change (subsequent calls).
67
52
  The getters/setters can be used in standard AR validations, Rails mass assignments/form helpers and so on.
68
53
 
69
- ==Gotchas
54
+
55
+ # Locale Awareness
56
+
57
+ has_setting has basic locale awareness. So when getting a setting, has_setting looks for the setting with the current locale. If it doesn't find it, it just grabs the first setting it finds, ignoring the locale.
58
+ When setting a setting, has_setting will look if a setting exists with the current locale and if not create a new settings record for the current locale.
59
+
60
+
61
+ # Gotchas
62
+
70
63
  * Values are stored as Strings in the DB. Values are converted with one of the formatters (depending on selected :type). If you try to store an unsupported type or anything other than the type you selected there might be an exception (i.e. if you try to store "foobar" as an :type => :int)
71
64
  * Currently there are no length validations on the 'name' and 'value' column of Setting. Take care not to store values to big. Especially when using the array formatters (:floats, :ints, :strings)
72
65
 
73
66
 
74
- ==Example
75
- <code>
67
+ # Example
68
+
69
+ ```
76
70
  class Foo < ActiveRecord::Base
77
71
  has_setting(:string_setting)
78
72
  has_setting(:another_string_setting, :type => :string)
@@ -101,12 +95,43 @@ foo.float_setting
101
95
  foo.float_setting = nil
102
96
  foo.float_setting
103
97
  => nil
104
-
105
- </code>
98
+ ```
106
99
 
107
100
 
108
- ==Todo
101
+ # Todo
102
+
109
103
  has_setting should stay as simple as possible... still some ideas are around:
110
104
  * Custom formatter (to convert arbitrary objects, i.e. Date/Time/DateTime...)
111
105
  * Add validation options
112
106
 
107
+ # History
108
+
109
+ * 0.5:
110
+ * Added basic locale awareness. If you update from a previous version, you need to add a locale column to the settings table.
111
+ * 0.4.3:
112
+ * Changed behaviour of :boolean formatters: Now they treat '0', 0, false, nil and '' as false, everything else as true
113
+ This is not the same behaviour as ruby (treating only nil and false as false) but should help with input from web forms (i.e. checkboxes)
114
+ If you want strict ruby boolean behaviour, then use :strict_boolean as :type
115
+ * 0.4.2:
116
+ * bug fixes for boolean types default values
117
+ * 0.3.10:
118
+ * added boolean and booleans formatters
119
+ * 0.3.9:
120
+ * added type :strings, :floats, :ints. They store the contents of an array as a comma separated string.
121
+ * 0.3.8:
122
+ * added dependent destroy option. no more zombie settings lingering around.
123
+ * 0.3.7:
124
+ * Gem is now built using jeweler... after messing around and bumping versions and getting
125
+ strange errors, this is 'it works' feeling coming back
126
+ * 0.3.4:
127
+ * Added custom formatter support. no new formatters though...
128
+ * 0.3.1:
129
+ * Bug Fixed: has_many(:settings) is not added to ActiveRecord::Base but only to the classes with has_setting
130
+ * Bug Fixed: options are not shared between classes
131
+ * Again changed the way settings are saved. Save is now done on parent.save with an after_save callback. (like this the settings are treated as if they were attributes of the owner)
132
+ * 0.2.x:
133
+ * Added :default option
134
+ * changed way settings are saved so that unsaved parents can have settings too
135
+ * changed nameing scheme of setting names (incompatible with versions prior 0.2.x but since nobody uses the gem i dont care :-))
136
+ * 0.1.x: First Version
137
+
data/lib/.DS_Store ADDED
Binary file
@@ -11,7 +11,7 @@ module HasSetting
11
11
  self.class_eval do
12
12
  unless @has_setting_options # define only once
13
13
  # AR association to settings
14
- has_many( :settings, :as => :owner, :class_name => 'HasSetting::Setting',
14
+ has_many( :settings, :as => :owner, :class_name => 'HasSetting::Setting',
15
15
  :foreign_key => :owner_id, :dependent => :destroy)
16
16
  after_save(:save_has_setting_association)
17
17
  @has_setting_options = {}
@@ -33,8 +33,7 @@ module HasSetting
33
33
 
34
34
  # default options
35
35
  type = options[:type] || :string # treat as string
36
- # default could be false, thats why we use has_key?
37
- default = options[:default] || (options.has_key?(:default) ? options[:default] : nil) # no default
36
+ options[:localize] ||= false
38
37
  self.has_setting_options[name] = options
39
38
 
40
39
  # setter
@@ -46,8 +45,8 @@ module HasSetting
46
45
  # getter
47
46
  define_method(name) do |*args|
48
47
  setting = read_setting(name)
49
- options = args.first || self.class.has_setting_options[name]
50
- return options[:default] if setting.nil?
48
+ options = args.first || has_setting_option(name)
49
+ return options[:default] if setting.nil?
51
50
  formatter = Formatters.for_type(options[:type] || type)
52
51
  formatter.to_type(setting.value)
53
52
  end
@@ -56,16 +55,36 @@ module HasSetting
56
55
 
57
56
  def write_setting(name, value)
58
57
  # find an existing setting or build a new one
59
- setting = self.settings.detect() {|item| item.name == name and item.locale.to_s == I18n.locale.to_s }
60
- setting = self.settings.build(:name => name, locale: I18n.locale.to_s) if setting.blank?
58
+ locale = localize?(name) ? I18n.locale : nil
59
+ setting = self.settings.detect() {|item| item.name == name and item.locale.to_s == locale.to_s }
60
+ setting = self.settings.build(:name => name, locale: locale) if setting.blank?
61
61
  setting.value = value
62
62
  end
63
63
 
64
64
  def read_setting(name)
65
- # use detect instead of SQL find. like this the 'cached' has_many-collection is inited
65
+ # use detect instead of SQL find. like this the 'cached' has_many-collection is inited
66
66
  # only once
67
- s = self.settings.detect() {|item| item.name == name and item.locale.to_s == I18n.locale.to_s} # first see if there is a setting with current locale
67
+ locale = localize?(name) ? I18n.locale.to_s : nil
68
+ s = self.settings.detect() {|item| item.name == name and item.locale.to_s == locale} # first see if there is a setting with current locale
68
69
  s ||= self.settings.detect() {|item| item.name == name} # then if not found, take the first setting with matching name (TODO: add locale fallbacks)
69
70
  s
70
71
  end
72
+
73
+ def localize? name
74
+ options = has_setting_option name
75
+ options ? options[:localize] : false
76
+ end
77
+
78
+ def has_setting_option name
79
+ klass = self.class
80
+ option = klass.has_setting_options ? klass.has_setting_options[name] : nil
81
+ while option.nil? and
82
+ klass.superclass != ActiveRecord::Base and
83
+ klass.superclass.respond_to?(:has_setting_options)
84
+ klass = klass.superclass
85
+ option = klass.has_setting_options[name]
86
+ end
87
+ option
88
+ end
89
+
71
90
  end
@@ -1,3 +1,3 @@
1
1
  module HasSetting
2
- VERSION = "0.5"
2
+ VERSION = "0.6"
3
3
  end
data/test/bar.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  class Bar < ActiveRecord::Base
2
- has_setting(:setting_1)
2
+ has_setting(:setting_1, localize: true)
3
3
  has_setting(:setting_2, :type => :int)
4
4
  end
data/test/test_helper.rb CHANGED
@@ -5,9 +5,9 @@ require 'test/unit'
5
5
  require File.dirname(__FILE__) + '/../lib/has_setting'
6
6
 
7
7
 
8
- ActiveRecord::Base.establish_connection(
9
- :adapter => 'sqlite3',
10
- :database => 'test.sqlite3',
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => 'sqlite3',
10
+ :database => 'test.sqlite3',
11
11
  :timeout => 5000
12
12
  )
13
13
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: has_setting
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: '0.6'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-04-10 00:00:00.000000000 Z
13
+ date: 2013-06-07 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: Stores settings as key/value pairs in a settings table and provides accessors
16
16
  for them on the owning object
@@ -22,11 +22,12 @@ extensions: []
22
22
  extra_rdoc_files: []
23
23
  files:
24
24
  - .gitignore
25
- - README
25
+ - README.md
26
26
  - Rakefile
27
27
  - VERSION.yml
28
28
  - has_setting.gemspec
29
29
  - help/001_create_settings.rb
30
+ - lib/.DS_Store
30
31
  - lib/has_setting.rb
31
32
  - lib/has_setting/ar_extensions.rb
32
33
  - lib/has_setting/formatters.rb
@@ -59,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
59
60
  version: '0'
60
61
  requirements: []
61
62
  rubyforge_project:
62
- rubygems_version: 1.8.24
63
+ rubygems_version: 1.8.25
63
64
  signing_key:
64
65
  specification_version: 3
65
66
  summary: Simple setting extension to AR