simplificator-has_setting 0.2.0 → 0.3.6
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/VERSION.yml +4 -0
- data/lib/has_setting.rb +8 -2
- data/lib/has_setting/ar_extensions.rb +45 -35
- data/lib/has_setting/formatters.rb +72 -0
- data/lib/has_setting/setting.rb +1 -1
- data/test/baz.rb +2 -0
- data/test/test_helper.rb +8 -7
- data/test/unit/formatters_test.rb +66 -0
- data/test/unit/has_setting_test.rb +12 -1
- metadata +18 -11
data/VERSION.yml
ADDED
data/lib/has_setting.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# Intialize the gem by including some extension to ActiveRecord::Base
|
2
2
|
require File.dirname(__FILE__) + '/has_setting/ar_extensions'
|
3
|
+
require File.dirname(__FILE__) + '/has_setting/formatters'
|
3
4
|
require File.dirname(__FILE__) + '/has_setting/setting'
|
4
5
|
ActiveRecord::Base.class_eval do
|
5
6
|
include(HasSetting::InstanceMethods)
|
6
7
|
extend(HasSetting::ClassMethods)
|
7
|
-
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
HasSetting::Formatters.register_formatter(:string, HasSetting::Formatters::StringFormatter.new)
|
12
|
+
HasSetting::Formatters.register_formatter(:float, HasSetting::Formatters::FloatFormatter.new)
|
13
|
+
HasSetting::Formatters.register_formatter(:int, HasSetting::Formatters::IntFormatter.new)
|
@@ -1,17 +1,11 @@
|
|
1
1
|
module HasSetting
|
2
|
+
|
2
3
|
module InstanceMethods
|
3
4
|
def write_setting(name, value)
|
4
5
|
# find an existing setting or build a new one
|
5
|
-
setting = self.settings.
|
6
|
+
setting = self.settings.detect() {|item| item.name == name }
|
6
7
|
setting = self.settings.build(:name => name) if setting.blank?
|
7
8
|
setting.value = value
|
8
|
-
# save only if parent has been saved. else we expect a parent.save call
|
9
|
-
# which will cascade to the children since they were created with build()
|
10
|
-
unless self.new_record?
|
11
|
-
setting.save
|
12
|
-
# reload collection so the read_setting() finds the settings with 'detect()'
|
13
|
-
self.settings.reload
|
14
|
-
end
|
15
9
|
end
|
16
10
|
|
17
11
|
def read_setting(name)
|
@@ -22,45 +16,61 @@ module HasSetting
|
|
22
16
|
end
|
23
17
|
|
24
18
|
module ClassMethods
|
25
|
-
def self.extended(extender)
|
26
|
-
extender.class_eval do
|
27
|
-
# AR association to settings
|
28
|
-
has_many(:settings, :as => :owner, :class_name => 'HasSetting::Setting', :foreign_key => :owner_id)
|
29
|
-
# a hash where we can store options for the settings
|
30
|
-
write_inheritable_attribute(:has_setting_options, {})
|
31
|
-
class_inheritable_reader(:has_setting_options)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
#
|
38
19
|
# Setup of the getter/setter
|
39
20
|
def has_setting(name, options = {})
|
40
21
|
name = name.to_s
|
41
|
-
raise ArgumentError.new(
|
42
|
-
|
22
|
+
raise ArgumentError.new('Setting name must not be blank') if name.blank?
|
23
|
+
|
24
|
+
self.class_eval do
|
25
|
+
unless @has_setting_options # define only once
|
26
|
+
# AR association to settings
|
27
|
+
has_many(:settings, :as => :owner, :class_name => 'HasSetting::Setting', :foreign_key => :owner_id)
|
28
|
+
after_save(:save_has_setting_association)
|
29
|
+
@has_setting_options = {}
|
30
|
+
def self.has_setting_options
|
31
|
+
@has_setting_options
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
# Callback to save settings
|
36
|
+
def save_has_setting_association
|
37
|
+
self.settings.each do |setting|
|
38
|
+
if setting.changed?
|
39
|
+
setting.save
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
raise ArgumentError.new("Setting #{name }is already defined on #{self.name}") if self.has_setting_options.has_key?(name)
|
49
|
+
|
50
|
+
# default options
|
43
51
|
options[:type] ||= :string # treat as string
|
44
52
|
options[:default] ||= nil # no default value
|
45
|
-
has_setting_options[name] = options
|
53
|
+
self.has_setting_options[name] = options
|
46
54
|
|
55
|
+
# setter
|
47
56
|
define_method("#{name}=".intern) do |value|
|
48
|
-
|
49
|
-
write_setting(name, value)
|
57
|
+
formatter = HasSetting::Formatters.for_type(options[:type])
|
58
|
+
write_setting(name, formatter.to_s(value))
|
50
59
|
end
|
51
60
|
|
52
61
|
# getter
|
53
|
-
define_method(name) do |*args|
|
62
|
+
define_method(name) do |*args|
|
54
63
|
setting = read_setting(name)
|
55
|
-
options = args.first || has_setting_options[name]
|
64
|
+
options = args.first || self.class.has_setting_options[name]
|
56
65
|
return options[:default] if setting.nil?
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
66
|
+
formatter = HasSetting::Formatters.for_type(options[:type])
|
67
|
+
formatter.to_type(setting.value)
|
68
|
+
#case options[:type]
|
69
|
+
# when :string : setting.value
|
70
|
+
# when :int : setting.value.nil? ? nil : setting.value.to_i
|
71
|
+
# when :float : setting.value.nil? ? nil : setting.value.to_f
|
72
|
+
# else raise ArgumentError.new("Unsupported type: #{options[:type]}")
|
73
|
+
#end
|
64
74
|
end
|
65
75
|
end
|
66
76
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module HasSetting
|
2
|
+
module Formatters
|
3
|
+
@@formatters = {}
|
4
|
+
#
|
5
|
+
# register a formatter:
|
6
|
+
# * type: a Symbol that is used to identify this formatter in the has_setting options hash via the :type option
|
7
|
+
# * formatter: the formatter, an object which supports to_type and to_s methods
|
8
|
+
def self.register_formatter(type, formatter)
|
9
|
+
if !formatter.respond_to?(:to_s) || !formatter.respond_to?(:to_type)
|
10
|
+
raise ArgumentError.new('Formatter does not support to_s/to_type')
|
11
|
+
end
|
12
|
+
@@formatters[type] = formatter
|
13
|
+
end
|
14
|
+
|
15
|
+
# Lookup a Formatter by type symbol
|
16
|
+
# raises ArgumentError if the formatter is not found
|
17
|
+
def self.for_type(type)
|
18
|
+
formatter = @@formatters[type]
|
19
|
+
raise ArgumentError.new("Can not find a formatter for #{type}") unless formatter
|
20
|
+
formatter
|
21
|
+
end
|
22
|
+
|
23
|
+
# Helper class which handles nil values
|
24
|
+
class NilSafeFormatter
|
25
|
+
# Converts the String from DB to the specified type
|
26
|
+
# Nil is returned for nil values
|
27
|
+
def to_type(value)
|
28
|
+
safe_to_type(value) unless value == nil
|
29
|
+
end
|
30
|
+
# Converts the value to String for storing in DB
|
31
|
+
# Nil is returned for nil values
|
32
|
+
def to_s(value)
|
33
|
+
safe_to_s(value) unless value == nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Formatter for Strings
|
38
|
+
class StringFormatter < NilSafeFormatter
|
39
|
+
def to_type(value)
|
40
|
+
value
|
41
|
+
end
|
42
|
+
def safe_to_s(value)
|
43
|
+
value.to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
# Formatter for ints
|
47
|
+
# Throws ArgumentError if value can not be converted
|
48
|
+
class IntFormatter < NilSafeFormatter
|
49
|
+
# Integer() does not treat "2.6" the same as 2.6
|
50
|
+
# while 2.6 is a valid Intger() (-> 2), "2.6" is not.
|
51
|
+
# Note that "2" is a valid argument for Integer() and that "".to_i is valid
|
52
|
+
# while Integer('') is not...
|
53
|
+
# Circumvent this by first convert with Float() so everything obeys to the same rules
|
54
|
+
def safe_to_type(value)
|
55
|
+
Integer(Float(value))
|
56
|
+
end
|
57
|
+
def safe_to_s(value)
|
58
|
+
Integer(Float(value)).to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
# Formatter for float values
|
62
|
+
# Throws ArgumentError if value can not be converted
|
63
|
+
class FloatFormatter < NilSafeFormatter
|
64
|
+
def safe_to_type(value)
|
65
|
+
Float(value)
|
66
|
+
end
|
67
|
+
def safe_to_s(value)
|
68
|
+
Float(value).to_s
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/has_setting/setting.rb
CHANGED
data/test/baz.rb
ADDED
data/test/test_helper.rb
CHANGED
@@ -12,8 +12,9 @@ ActiveRecord::Base.establish_connection(
|
|
12
12
|
)
|
13
13
|
|
14
14
|
ActiveRecord::Base.connection.drop_table(:settings) rescue ActiveRecord::StatementInvalid
|
15
|
-
|
16
|
-
ActiveRecord::Base.connection.drop_table(
|
15
|
+
[:foos, :bars, :bazs].each do |table|
|
16
|
+
ActiveRecord::Base.connection.drop_table(table) rescue ActiveRecord::StatementInvalid
|
17
|
+
end
|
17
18
|
|
18
19
|
|
19
20
|
|
@@ -23,13 +24,13 @@ ActiveRecord::Base.connection.create_table(:settings) do |table|
|
|
23
24
|
table.string(:owner_type, :limit => 255, :null => false)
|
24
25
|
table.integer(:owner_id, :null => false)
|
25
26
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
[:foos, :bars, :bazs].each do |table|
|
28
|
+
ActiveRecord::Base.connection.create_table(table) do |t|
|
29
|
+
end
|
29
30
|
end
|
30
|
-
|
31
31
|
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
32
32
|
ActiveRecord::Base.logger.level = Logger::DEBUG # change to DEBUG if you want to see something :-)
|
33
33
|
|
34
34
|
require File.join(File.dirname(__FILE__), 'foo')
|
35
|
-
require File.join(File.dirname(__FILE__), 'bar')
|
35
|
+
require File.join(File.dirname(__FILE__), 'bar')
|
36
|
+
require File.join(File.dirname(__FILE__), 'baz')
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
include HasSetting
|
3
|
+
class FormattersTest < Test::Unit::TestCase
|
4
|
+
def test_for_type
|
5
|
+
[:string, :float, :int].each do |symbol|
|
6
|
+
assert(Formatters.for_type(symbol), "No formatter for #{symbol}")
|
7
|
+
end
|
8
|
+
assert_raises(ArgumentError) do
|
9
|
+
Formatters.for_type(:rarararararara_i_do_not_exist)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_string_formatter()
|
14
|
+
f = Formatters::StringFormatter.new
|
15
|
+
assert_equal('', f.to_s(''))
|
16
|
+
assert_equal('a', f.to_s('a'))
|
17
|
+
assert_equal('', f.to_type(''))
|
18
|
+
assert_equal('a', f.to_type('a'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_int_formatter()
|
22
|
+
f = Formatters::IntFormatter.new
|
23
|
+
assert_raises(ArgumentError) do
|
24
|
+
f.to_s('')
|
25
|
+
end
|
26
|
+
assert_raises(ArgumentError) do
|
27
|
+
f.to_s('asas')
|
28
|
+
end
|
29
|
+
assert_nil(f.to_s(nil))
|
30
|
+
assert_equal('2', f.to_s(2.6))
|
31
|
+
assert_equal('2', f.to_s(2))
|
32
|
+
|
33
|
+
assert_raises(ArgumentError) do
|
34
|
+
f.to_type('')
|
35
|
+
end
|
36
|
+
assert_raises(ArgumentError) do
|
37
|
+
f.to_type('asas')
|
38
|
+
end
|
39
|
+
assert_nil(f.to_type(nil))
|
40
|
+
assert_equal(2, f.to_type('2'))
|
41
|
+
assert_equal(2, f.to_type('2.6'))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_float_formatter()
|
45
|
+
f = Formatters::FloatFormatter.new
|
46
|
+
assert_raises(ArgumentError) do
|
47
|
+
f.to_s('')
|
48
|
+
end
|
49
|
+
assert_raises(ArgumentError) do
|
50
|
+
f.to_s('asas')
|
51
|
+
end
|
52
|
+
assert_nil(f.to_s(nil))
|
53
|
+
assert_equal('2.6', f.to_s(2.6))
|
54
|
+
assert_equal('2.0', f.to_s(2))
|
55
|
+
|
56
|
+
assert_raises(ArgumentError) do
|
57
|
+
f.to_type('')
|
58
|
+
end
|
59
|
+
assert_raises(ArgumentError) do
|
60
|
+
f.to_type('asas')
|
61
|
+
end
|
62
|
+
assert_nil(f.to_type(nil))
|
63
|
+
assert_equal(2.0, f.to_type('2'))
|
64
|
+
assert_equal(2.6, f.to_type('2.6'))
|
65
|
+
end
|
66
|
+
end
|
@@ -4,9 +4,10 @@ class HasSettingTest < Test::Unit::TestCase
|
|
4
4
|
def setup()
|
5
5
|
@foo = Foo.create!
|
6
6
|
@bar = Bar.create!
|
7
|
+
@baz = Baz.create!
|
7
8
|
end
|
8
9
|
|
9
|
-
def
|
10
|
+
def test_setting_has_accessors
|
10
11
|
assert @foo.respond_to?(:setting_1)
|
11
12
|
assert @foo.respond_to?(:setting_1=)
|
12
13
|
end
|
@@ -21,6 +22,7 @@ class HasSettingTest < Test::Unit::TestCase
|
|
21
22
|
def test_write_setting
|
22
23
|
count_before = HasSetting::Setting.count
|
23
24
|
@foo.write_setting('name', 'value1')
|
25
|
+
@foo.save!
|
24
26
|
assert_equal(count_before + 1, HasSetting::Setting.count)
|
25
27
|
setting = @foo.read_setting('name')
|
26
28
|
assert setting
|
@@ -37,6 +39,7 @@ class HasSettingTest < Test::Unit::TestCase
|
|
37
39
|
count_before = HasSetting::Setting.count
|
38
40
|
assert(!@foo.setting_1)
|
39
41
|
@foo.setting_1 = 'bli'
|
42
|
+
@foo.save!
|
40
43
|
assert_equal(count_before + 1, HasSetting::Setting.count)
|
41
44
|
assert_equal('bli', @foo.setting_1)
|
42
45
|
@foo.setting_1 = 'bla'
|
@@ -46,12 +49,15 @@ class HasSettingTest < Test::Unit::TestCase
|
|
46
49
|
def test_different_classes_do_not_share_setting
|
47
50
|
count_before = HasSetting::Setting.count
|
48
51
|
@foo.setting_1 = 'foo'
|
52
|
+
@foo.save!
|
49
53
|
@bar.setting_1 = 'bar'
|
54
|
+
@bar.save!
|
50
55
|
assert_equal(count_before + 2, HasSetting::Setting.count)
|
51
56
|
|
52
57
|
assert_equal('foo', @foo.setting_1)
|
53
58
|
assert_equal('bar', @bar.setting_1)
|
54
59
|
end
|
60
|
+
|
55
61
|
|
56
62
|
def test_has_nil_setting
|
57
63
|
@foo.setting_1 = nil
|
@@ -95,4 +101,9 @@ class HasSettingTest < Test::Unit::TestCase
|
|
95
101
|
assert_equal('radabumm', my_foo.with_default)
|
96
102
|
end
|
97
103
|
|
104
|
+
def test_not_everyone_has_settings_association
|
105
|
+
assert_equal(true, @foo.respond_to?(:settings))
|
106
|
+
assert_equal(true, @bar.respond_to?(:settings))
|
107
|
+
assert_equal(false, @baz.respond_to?(:settings))
|
108
|
+
end
|
98
109
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simplificator-has_setting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simplificator GmbH
|
@@ -9,12 +9,12 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-02-
|
12
|
+
date: 2009-02-04 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description:
|
17
|
-
email:
|
16
|
+
description: TODO
|
17
|
+
email: pascal.betz@simplificator.com
|
18
18
|
executables: []
|
19
19
|
|
20
20
|
extensions: []
|
@@ -22,19 +22,26 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
-
-
|
25
|
+
- VERSION.yml
|
26
|
+
- lib/has_setting
|
26
27
|
- lib/has_setting/ar_extensions.rb
|
28
|
+
- lib/has_setting/formatters.rb
|
27
29
|
- lib/has_setting/setting.rb
|
30
|
+
- lib/has_setting.rb
|
28
31
|
- test/bar.rb
|
32
|
+
- test/baz.rb
|
29
33
|
- test/foo.rb
|
30
34
|
- test/test_helper.rb
|
35
|
+
- test/unit
|
36
|
+
- test/unit/formatters_test.rb
|
31
37
|
- test/unit/has_setting_test.rb
|
32
|
-
-
|
33
|
-
has_rdoc:
|
34
|
-
homepage: http://
|
38
|
+
- test/unit/test.sqlite3
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/pascalbetz/has_setting
|
35
41
|
post_install_message:
|
36
|
-
rdoc_options:
|
37
|
-
|
42
|
+
rdoc_options:
|
43
|
+
- --inline-source
|
44
|
+
- --charset=UTF-8
|
38
45
|
require_paths:
|
39
46
|
- lib
|
40
47
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -55,6 +62,6 @@ rubyforge_project:
|
|
55
62
|
rubygems_version: 1.2.0
|
56
63
|
signing_key:
|
57
64
|
specification_version: 2
|
58
|
-
summary:
|
65
|
+
summary: TODO
|
59
66
|
test_files: []
|
60
67
|
|