settings_lord 1.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/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 [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.md ADDED
@@ -0,0 +1,99 @@
1
+ #SettingsLord
2
+ Easy way to manage your site settings
3
+
4
+ ##Why?
5
+ Because we should create more cms-ready gems for rails.
6
+
7
+ ##Requirements
8
+ Rails 3 only
9
+
10
+ ##Install
11
+ add to your Gemfile:
12
+
13
+ gem 'settings_lord'
14
+
15
+ ##Overview
16
+ You can create settings via class methods:
17
+
18
+ class Setting < ActiveRecord::Base
19
+
20
+ settings do
21
+ site_name :default => "RockBlogger"
22
+ end
23
+
24
+ end
25
+
26
+ After this you will be able to manipulate this setting:
27
+
28
+ Setting.site_name # => "RockBlogger"
29
+ Setting.site_name = "My blog about software"
30
+ Setting.site_name # => "My blog about software"
31
+
32
+
33
+ You can store your settings in namespaces:
34
+
35
+ # in class body
36
+ settings :site do
37
+ name :default => "RockBlogger"
38
+ end
39
+
40
+ # any other place
41
+ Setting.site.name # => "RockBlogger"
42
+ Setting.site.name = "Rails notes"
43
+ Setting.site.name # => "Rails notes"
44
+
45
+
46
+ What about settings freezing?
47
+
48
+ settings :site do
49
+ developed_by :default => "Pechorin Andrey", :as_frozen => true
50
+ end
51
+
52
+ Setting.site.created_by # => "Pechorin Andrey"
53
+ Setting.site.created_by = "some other person" # => will raise NoMethodError
54
+
55
+ You can cast values in many ways:
56
+
57
+ settings do
58
+ year :default => 1990, :cast => lambda {|value| value.to_s + " year is now!"}
59
+ should_be_integer :default => 10 # will store 10 as string in database, but automatically create cast symbol -> :to_i
60
+ should_be_integer_with_cast :default => '10', :cast => :to_i
61
+ end
62
+
63
+ Setting.year # => "1990 year is now!"
64
+ Setting.year = 2011
65
+ Setting.year # => "2011 year is now!"
66
+
67
+ Setting.should_be_integer.class # => Fixnum
68
+ Setting.should_be_integer_with_cast.class # => Fixnum
69
+
70
+ What about booleans settings?
71
+
72
+ settings :blog_settings do
73
+ comments_are_closed :default => false, :as_boolean => true
74
+ end
75
+
76
+ Setting.blog_settings.comments_are_closed # => false
77
+ Setting.blog_settings.comments_are_closed = 10 # will cast 10 to true/false value ;)
78
+ Setting.blog_settings.comments_are_closed # => true
79
+
80
+ You can limit accepted values:
81
+
82
+ settings do
83
+ posts_per_page :accepted_values => 2..20 # Range
84
+ locale :accepted_values => [:ru,:en] # Array
85
+ support_email :accepted_values => /support@regexp/ # Regexp
86
+ end
87
+
88
+ Setting.posts_per_page = 12 # ok
89
+ Setting.posts_per_page = 30 # => will raise Exception
90
+
91
+ All settings stored in database, but you can use in-memory settings
92
+
93
+ settings do
94
+ memory_option :storage => :memory
95
+ end
96
+
97
+ ##What next?
98
+ * integration with other storages
99
+ * \_default\_value, \_before\_cast
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,16 @@
1
+ require 'rails/generators'
2
+
3
+ class SettingsLordGenerator < Rails::Generators::Base
4
+
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ def generate_settings_lord
8
+ copy_file "migration.rb", "db/migrate/#{migration_time}_create_settings.rb"
9
+ copy_file "setting.rb", "app/models/setting.rb"
10
+ end
11
+
12
+ def migration_time
13
+ Time.now.strftime('%Y%m%d%H%M%S')
14
+ end
15
+
16
+ end
@@ -0,0 +1,14 @@
1
+ class CreateSettings < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :settings do |t|
4
+ t.string :name
5
+ t.text :value
6
+ t.string :klass
7
+ t.integer :parent_id
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :settings
13
+ end
14
+ end
@@ -0,0 +1,2 @@
1
+ class Setting < ActiveRecord::Base
2
+ end
@@ -0,0 +1,43 @@
1
+ module SettingsLord::ActiveRecord
2
+
3
+ module ClassMethods
4
+
5
+ def settings(namespace = nil,*args,&block)
6
+ SettingsLord.check_active_record!
7
+ self.send(:extend, SettingsLord::ActiveRecord::MethodMissing)
8
+
9
+ SettingsLord.setting_creator.klass = self
10
+ SettingsLord.setting_creator.parent = create_parent_by_namespace(namespace)
11
+ SettingsLord.setting_creator.instance_eval &block
12
+ end
13
+
14
+ def create_parent_by_namespace(namespace)
15
+ namespace ? Setting.find_or_create_by_name_and_klass_and_parent_id_and_value(namespace.to_s.underscore, self.model_name.underscore, nil, nil) : nil
16
+ end
17
+
18
+ def find_parent_by_namespace(namespace,klass)
19
+ Setting.find_by_name_and_parent_id_and_klass(namespace.to_s,nil,klass)
20
+ end
21
+
22
+ end
23
+
24
+ module MethodMissing
25
+
26
+ def method_missing(name,*args,&block)
27
+ result = SettingsLord::Reflector.new(:name => name, :new_value => args.first, :klass => self).reflect
28
+
29
+ if result.is_a? SettingsLord::MetaSetting
30
+ return result.get_value
31
+ # for setters
32
+ elsif result.present?
33
+ return result
34
+ # for others
35
+ else
36
+ super(name,*args,&block)
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,22 @@
1
+ module SettingsLord
2
+
3
+ ACTIVE_RECORD_COLUMNS = ['name','value','klass','parent_id']
4
+
5
+ mattr_accessor :setting_creator
6
+ mattr_accessor :meta_settings
7
+
8
+ def self.check_active_record!
9
+ ACTIVE_RECORD_COLUMNS.each do |column|
10
+ unless Setting.column_names.include?(column)
11
+ raise Exception, "Column '#{column}' doesn't exists in class #{self.name}!"
12
+ end
13
+ end
14
+ end
15
+
16
+ # Objects pool
17
+ def self.setup_plugin!
18
+ self.meta_settings ||= MetaSettingCollection.new
19
+ self.setting_creator ||= SettingCreator.new
20
+ end
21
+
22
+ end
@@ -0,0 +1,120 @@
1
+ class SettingsLord::MetaSetting
2
+
3
+ def initialize(*args)
4
+ setup_attributes!(args)
5
+ setup_active_record_object!
6
+ end
7
+
8
+ def similar_to?(target)
9
+ if target.respond_to? :parent
10
+ @name == target.name && @klass == target.klass && @parent == target.parent
11
+ else
12
+ @name == target.name && @klass == target.klass
13
+ end
14
+ end
15
+
16
+ def update_value(new_value)
17
+ raise NoMethodError if @as_frozen == true
18
+
19
+ case @accepted_values
20
+ when Range, Array
21
+ raise Exception unless @accepted_values.include?(new_value)
22
+ when Regexp
23
+ raise Exception unless !!(new_value.match(@accepted_values))
24
+ end
25
+
26
+ case @storage
27
+ when :active_record
28
+ record = Setting.find(@active_record_id)
29
+ if @as_boolean
30
+ bool = !!new_value ? '1' : '0'
31
+ record.update_attribute :value, bool
32
+ else
33
+ record.update_attribute :value, new_value
34
+ end
35
+ when :memory
36
+ if @as_boolean
37
+ @value = !!new_value
38
+ else
39
+ @value = new_value
40
+ end
41
+ end
42
+ end
43
+
44
+ def get_value
45
+ cast_value(extract_data,@cast)
46
+ end
47
+
48
+ def formatted_klass_name
49
+ @klass.to_s.underscore.to_sym
50
+ end
51
+
52
+ def setup_attributes!(args)
53
+ options = args.extract_options!
54
+
55
+ options.each do |key,value|
56
+ self.class.send :attr_accessor, key
57
+ self.send "#{key.to_s}=", value
58
+ end
59
+
60
+ @klass = formatted_klass_name
61
+ end
62
+
63
+ protected
64
+
65
+ def setup_active_record_object!
66
+ if @storage == :active_record
67
+
68
+ # find or create object
69
+ if @parent
70
+ parent_record = Setting.find_parent_by_namespace(@parent,@klass)
71
+ record = Setting.find_or_create_by_klass_and_name_and_parent_id(@klass,@name,parent_record.id)
72
+ else
73
+ record = Setting.find_or_create_by_klass_and_name(@klass,@name)
74
+ end
75
+
76
+ # setup value if needed
77
+ if record.value.nil?
78
+ if @as_boolean
79
+ bool_value = (!!@default ? '1' : '0')
80
+ record.update_attribute :value, bool_value
81
+ else
82
+ record.update_attribute :value, @default
83
+ end
84
+ end
85
+
86
+ # hold acrive record id to fast search
87
+ self.class.send :attr_accessor, :active_record_id
88
+ @active_record_id = record.id
89
+ end
90
+ end
91
+
92
+ def cast_value(value,cast_method = nil)
93
+ case cast_method
94
+ when Symbol
95
+ value.send(cast_method)
96
+ when Proc
97
+ cast_method.call(value)
98
+ else
99
+ value
100
+ end
101
+ end
102
+
103
+ def extract_data
104
+ result = case @storage
105
+ when :active_record
106
+ Setting.find(@active_record_id).value || @default
107
+ when :memory
108
+ @value || @default
109
+ end
110
+
111
+ if @as_boolean
112
+ result = result.to_i > 0 ? true : false
113
+ end
114
+
115
+ return result
116
+ end
117
+
118
+
119
+
120
+ end
@@ -0,0 +1,99 @@
1
+ class SettingsLord::MetaSettingCollection
2
+
3
+ VALID_KEYS = [:default,:accepted_values,:cast,:as_frozen,:as_boolean,:storage]
4
+ BOOL_KEYS = [:as_frozen,:as_boolean]
5
+
6
+ BOOL_CLASSES = [TrueClass,FalseClass]
7
+ DEFAULT_VALUE_CLASSES = [Fixnum,String]
8
+ ACCEPTED_VALUES_CLASSES = [Array,Range,Regexp]
9
+ CAST_CLASSES = [Symbol,Proc]
10
+ SET_AND_GET_KEYS = [:klass,:namespace,:name,:default_value,:new_value]
11
+
12
+ POSSIBLE_STORAGES = [:active_record,:memory]
13
+
14
+ attr_reader :collection # contains all MetaOption objects
15
+ attr_reader :klasses_and_namespaces # contains classes and namespaces for fast look-up
16
+
17
+ def initialize
18
+ @collection = []
19
+ @klasses_and_namespaces = {}
20
+ end
21
+
22
+ def add(meta_option)
23
+ return false unless meta_option.is_a? SettingsLord::MetaSetting
24
+
25
+ remove_if_exists(meta_option)
26
+ fill_klasses_and_namespaces_table(meta_option)
27
+ self.collection << meta_option
28
+ end
29
+
30
+ def has_klass?(klass_name)
31
+ self.klasses_and_namespaces.keys.include?(klass_name.to_sym)
32
+ end
33
+
34
+ def klass_has_namespace?(klass,namespace)
35
+ self.has_klass?(klass) and self.klasses_and_namespaces[klass].include?(namespace.to_sym)
36
+ end
37
+
38
+ def set_by(reflection)
39
+ reflection.name = remove_set_tag(reflection.name)
40
+
41
+ if meta_option = find_by_reflection(reflection)
42
+ meta_option.update_value(reflection.new_value)
43
+ else
44
+ return nil
45
+ end
46
+ end
47
+
48
+ def get_by(reflection)
49
+ find_by_reflection(reflection)
50
+ end
51
+
52
+ def find_by_reflection(reflection)
53
+ # we can't search without klass and name
54
+ return nil if reflection.klass.blank? || reflection.name.blank?
55
+
56
+ # check klass
57
+ return nil unless has_klass?(reflection.klass)
58
+
59
+ # check namespace if needed
60
+ if reflection.reflect_like_namespace
61
+ return nil unless klass_has_namespace?(reflection.klass, reflection.parent)
62
+ end
63
+
64
+ if reflection.reflect_like_namespace
65
+ result = @collection.select do |entry|
66
+ entry.klass == reflection.klass and entry.name == reflection.name and entry.parent == reflection.parent
67
+ end
68
+ else
69
+ result = @collection.select do |entry|
70
+ entry.klass == reflection.klass and entry.name == reflection.name
71
+ end
72
+ end
73
+
74
+ return result.first
75
+ end
76
+
77
+ private
78
+
79
+ # transfer :method_name= to :method_name
80
+ def remove_set_tag(target)
81
+ target.to_s.gsub(/=$/,'').to_sym
82
+ end
83
+
84
+ def remove_if_exists(target)
85
+ self.collection.each do |source|
86
+ self.collection.delete_if {|s| s.similar_to?(target)}
87
+ end
88
+ end
89
+
90
+ def fill_klasses_and_namespaces_table(option)
91
+ klass_name = option.formatted_klass_name
92
+ @klasses_and_namespaces[klass_name] ||= []
93
+ if option.respond_to? :parent
94
+ @klasses_and_namespaces[klass_name] << option.parent
95
+ @klasses_and_namespaces[klass_name].uniq!
96
+ end
97
+ end
98
+
99
+ end
@@ -0,0 +1,91 @@
1
+ class SettingsLord::Reflector
2
+ # reflector hold klass/namespace information and reflect on name
3
+
4
+ attr_accessor :name,:klass,:new_value,:reflect_like_namespace,:parent
5
+
6
+ def initialize(*args)
7
+ setup_instance_variables!(args)
8
+ end
9
+
10
+ # method missing will be called only when we return Reflector object
11
+ # this is default case when user attempt to nested option (option with namespace)
12
+ # for example:
13
+ #
14
+ # Option.view.default_path
15
+ #
16
+ # view method will return Reflecor object
17
+ #
18
+ # puts Option.view.class # => Optionator::Reflector
19
+ #
20
+ # default_path method will touch this method missing
21
+ #
22
+ # when we return Reflector object this object already get klass and namespace information
23
+ # we only need to setup called method name and some extra arguments
24
+ def method_missing(called_name,*args,&block)
25
+ @name = called_name.to_sym
26
+ @new_value = args.first
27
+
28
+ result = self.reflect
29
+
30
+ if result.is_a? SettingsLord::MetaSetting
31
+ return result.get_value
32
+ # for setters
33
+ elsif result.present?
34
+ return result
35
+ # for others
36
+ else
37
+ return nil
38
+ end
39
+ end
40
+
41
+ # search for proper MetaOption in MetaOptionCollection and get/set needed value
42
+ def reflect()
43
+ should_search = @meta.has_klass?(@klass) or @meta.klass_has_namespace?(@klass,@name)
44
+ return nil unless should_search
45
+
46
+ if is_getter?
47
+ return create_sub_reflection if should_create_sub_reflection?
48
+ return @meta.get_by(self)
49
+ else
50
+ return @meta.set_by(self)
51
+ end
52
+ end
53
+
54
+ def should_create_sub_reflection?
55
+ @reflect_like_namespace == false and @meta.klass_has_namespace?(@klass,@name)
56
+ end
57
+
58
+ def create_sub_reflection
59
+ reflection = self.dup
60
+ reflection.reflect_like_namespace = true
61
+ reflection.parent = reflection.name.to_sym
62
+ reflection.name = nil
63
+ return reflection
64
+ end
65
+
66
+ def is_getter?
67
+ not @name.to_s.end_with?('=')
68
+ end
69
+
70
+ def default_value_called?
71
+ !!@name.to_s.match(/[a-zA-Z0-9]_default_value/)
72
+ end
73
+
74
+ def remove_default_value_tag_from_string
75
+ @name.to_s.gsub(/_default_value/,'').to_sym
76
+ end
77
+
78
+ private
79
+
80
+ # @name/@parent/@klass should always be represented as Symbol
81
+ def setup_instance_variables!(args)
82
+ args = args.extract_options!
83
+ @name = args[:name].to_sym
84
+ @new_value = args[:new_value]
85
+ @klass = args[:klass]
86
+ @klass = args[:klass].model_name.underscore.to_sym if @klass.is_a? Class
87
+ @reflect_like_namespace = args[:reflect_like_namespace] || false
88
+ @meta = SettingsLord.meta_settings
89
+ end
90
+
91
+ end
@@ -0,0 +1,90 @@
1
+ class SettingsLord::SettingCreator
2
+
3
+ # OptionCreator process new option creation
4
+ #
5
+ # OptionCreator check conditions and defend you from some stupid options :)
6
+ # for example:
7
+ # you try to create option which can hold only true/false values ( :as_boolean => true )
8
+ # but in :default flag you write some integer ( :default => 100 )
9
+ # OptionCreator handle this situation and warn you about this.
10
+
11
+ attr_accessor :parent
12
+ attr_accessor :klass
13
+ attr_accessor :meta
14
+
15
+ def initialize
16
+ @meta = SettingsLord.meta_settings.class # holds class for easy access to constants
17
+ @meta_collection = SettingsLord.meta_settings # holds meta collection
18
+ end
19
+
20
+ # each option creates via method missing
21
+ #
22
+ # define_options :test do |option|
23
+ # option.super_option :default => 10 # => method_missing will be called with 'super_action' as "name" argument
24
+ # end
25
+ def method_missing(name,*args,&block)
26
+ options = args.extract_options!
27
+ options.assert_valid_keys(@meta::VALID_KEYS)
28
+ options = check_and_maintain_options(options)
29
+
30
+ options[:klass] = @klass # option should know class
31
+ options[:parent] = @parent.name.to_sym if @parent
32
+ options[:name] = name
33
+
34
+ new_meta_option = SettingsLord::MetaSetting.new(options)
35
+ @meta_collection.add(new_meta_option)
36
+ end
37
+
38
+ private
39
+
40
+ def check_and_maintain_options(options)
41
+ check_bool_flags(options)
42
+ check_and_setup_storage(options)
43
+ check_accepted_values_flag(options)
44
+ check_and_setup_cast_flag(options)
45
+ check_default_value_flag(options)
46
+ return options
47
+ end
48
+
49
+ def check_bool_flags(options)
50
+ @meta::BOOL_KEYS.each do |key|
51
+ if options[key] and not @meta::BOOL_CLASSES.include?(options[key].class)
52
+ raise Exception, "TrueClass or FalseClass expected but got instance of #{options[key].class} in #{key}"
53
+ end
54
+ end
55
+ end
56
+
57
+ def check_and_setup_storage(options)
58
+ options[:storage] ||= :active_record
59
+ raise Exception, "Possible storages is -> #{@meta::POSSIBLE_STORAGES.inspect}" unless @meta::POSSIBLE_STORAGES.include?(options[:storage])
60
+ # force setup value if storage is virtual
61
+ options[:value] = options[:default] if options[:storage] == :virtual
62
+ end
63
+
64
+ def check_accepted_values_flag(options)
65
+ if options[:accepted_values]
66
+ raise Exception,"Possible classes for :accepted_values flag is -> #{@meta::ACCEPTED_VALUES_CLASSES.inspect}, not a #{options[:accepted_values].class}" unless @meta::ACCEPTED_VALUES_CLASSES.include?(options[:accepted_values].class)
67
+ end
68
+ end
69
+
70
+ def check_and_setup_cast_flag(options)
71
+ if options[:cast]
72
+ raise Exception,"Possible classes for :cast flag is -> #{@meta::CAST_CLASSES}, not a #{options[:cast].class}" unless @meta::CAST_CLASSES.include?(options[:cast].class)
73
+ end
74
+ if options[:default] and options[:default].is_a? Fixnum and options[:cast].blank?
75
+ options[:cast] = :to_i
76
+ end
77
+ end
78
+
79
+ def check_default_value_flag(options)
80
+ if options[:as_boolean] == true and options[:default].present? and not @meta::BOOL_CLASSES.include?(options[:default].class)
81
+ raise Exception, 'true or false should be as default value'
82
+ else
83
+ if not options[:as_boolean] and options[:default] and not @meta::DEFAULT_VALUE_CLASSES.include?(options[:default].class)
84
+ raise Exception, "Possible classes for :default flag is -> #{@meta::DEFAULT_VALUE_CLASSES.inspect}, not a #{options[:default].class}"
85
+ end
86
+ end
87
+ end
88
+
89
+
90
+ end
@@ -0,0 +1,11 @@
1
+ module SettingsLord
2
+ module Version
3
+
4
+ MAJOR = 1
5
+ MINOR = 0
6
+ PATCH = 1
7
+
8
+ STRING = [MAJOR,MINOR,PATCH].compact.join('.')
9
+
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ $:.push File.dirname(__FILE__)
2
+
3
+ require 'active_support/core_ext/module/attribute_accessors'
4
+
5
+ require 'settings_lord/base'
6
+ require 'settings_lord/setting_creator'
7
+ require 'settings_lord/reflector'
8
+ require 'settings_lord/active_record'
9
+ require 'settings_lord/meta_setting'
10
+ require 'settings_lord/meta_setting_collection'
11
+ require 'settings_lord/version'
12
+
13
+ require 'generators/settings_lord/settings_lord_generator'
14
+
15
+ # setup plugin
16
+ ActiveRecord::Base.send :extend, SettingsLord::ActiveRecord::ClassMethods
17
+ SettingsLord.setup_plugin!
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require './lib/settings_lord/version.rb'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "settings_lord"
6
+ s.version = SettingsLord::Version::STRING
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["pechrorin_andrey"]
9
+ s.email = ["pechorin.andrey@gmail.com"]
10
+ s.homepage = "https://github.com/pechorin/settings_lord"
11
+ s.summary = %q{Best way to manage your site settings}
12
+ s.description = %q{Best way to manage your site settings}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- test/*`.split("\n")
16
+ s.require_paths = ["lib"]
17
+ end
@@ -0,0 +1,226 @@
1
+ require 'test_helper'
2
+
3
+ class SettingsLordTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ Setting.delete_all
7
+ SettingsLord.meta_settings.instance_variable_set :@collection, []
8
+ end
9
+
10
+ test "should accept only boolean values" do
11
+ assert_nothing_raised do
12
+ Setting.settings do
13
+ option :as_frozen => true
14
+ end
15
+ end
16
+
17
+ assert_raise Exception do
18
+ Setting.settings do
19
+ option :as_frozen => 1
20
+ end
21
+ end
22
+ end
23
+
24
+ test "should accept only known storage" do
25
+ assert_nothing_raised do
26
+ Setting.settings do
27
+ option :storage => :active_record
28
+ option_2 :storage => :memory
29
+ end
30
+ end
31
+
32
+ assert_raise Exception do
33
+ Setting.settings do
34
+ option :storage => :javadoc
35
+ end
36
+ end
37
+ end
38
+
39
+ test "should accept only symbols and proc for :cast" do
40
+ assert_raise Exception do
41
+ Setting.settings do
42
+ option :cast => [1,2,3]
43
+ end
44
+ end
45
+
46
+ assert_nothing_raised do
47
+ Setting.settings do
48
+ option :cast => :to_f
49
+ option_2 :cast => lambda {}
50
+ end
51
+ end
52
+ end
53
+
54
+ test "bool flag" do
55
+ assert_raise Exception do
56
+ Setting.settings do
57
+ option :as_boolean => true, :default => 2
58
+ end
59
+ end
60
+
61
+ assert_nothing_raised do
62
+ Setting.settings do
63
+ option :as_boolean => true, :default => false
64
+ end
65
+ end
66
+ end
67
+
68
+ test "default value flag" do
69
+ assert_raise Exception do
70
+ Setting.settings do
71
+ option :default => [1,2,3]
72
+ end
73
+ end
74
+
75
+ assert_nothing_raised do
76
+ Setting.settings do
77
+ option_1 :default => "Hello"
78
+ option_2 :default => 100
79
+ end
80
+ end
81
+ end
82
+
83
+ test "should not duplicate virtual meta options" do
84
+ collection = SettingsLord.meta_settings.collection
85
+ start_size = collection.size
86
+
87
+ Setting.settings do
88
+ name
89
+ end
90
+ assert collection.size == start_size + 1
91
+
92
+ Setting.settings do
93
+ anothet_name
94
+ end
95
+ assert collection.size == start_size + 2
96
+
97
+ Setting.settings do
98
+ name
99
+ end
100
+ assert collection.size == start_size + 2
101
+ end
102
+
103
+ test "should get right value" do
104
+
105
+ assert_raise NoMethodError do
106
+ Setting.number
107
+ end
108
+
109
+ Setting.settings do
110
+ number :default => 10
111
+ end
112
+
113
+ assert Setting.number == 10
114
+ end
115
+
116
+ test "automatic casting" do
117
+ Setting.settings do
118
+ a :default => 10
119
+ b :default => '10'
120
+ end
121
+
122
+ assert Setting.a == 10
123
+ assert Setting.b == '10'
124
+ end
125
+
126
+ test "casting" do
127
+ Setting.settings do
128
+ number :default => 10, :cast => :to_s
129
+ end
130
+
131
+ assert Setting.number == "10"
132
+
133
+ Setting.settings do
134
+ number :default => 10, :cast => lambda {|value| value.to_s << "!!!"}
135
+ end
136
+
137
+ assert Setting.number == "10!!!"
138
+ end
139
+
140
+ test "set option" do
141
+ Setting.settings do
142
+ number :default => 10
143
+ end
144
+
145
+ Setting.number = 20
146
+ assert Setting.number == 20
147
+ end
148
+
149
+ test "frozen options" do
150
+ Setting.settings do
151
+ number :default => 10, :as_frozen => true
152
+ end
153
+
154
+ assert_raise NoMethodError do
155
+ Setting.number = 20
156
+ end
157
+ end
158
+
159
+ test 'in-memory options' do
160
+ Setting.settings do
161
+ in_memory_number :default => 10, :storage => :memory
162
+ end
163
+
164
+ assert Setting.find_by_name('in_memory_number') == nil && Setting.in_memory_number == 10
165
+
166
+ Setting.in_memory_number = 30
167
+ assert Setting.in_memory_number == 30
168
+ end
169
+
170
+ test 'as_boolean options' do
171
+ Setting.settings do
172
+ bool_value :default => true, :as_boolean => true
173
+ end
174
+
175
+ assert Setting.find_by_name('bool_value').value == '1' && Setting.bool_value.is_a?(TrueClass)
176
+
177
+ Setting.bool_value = false
178
+ assert Setting.find_by_name('bool_value').value == '0' && Setting.bool_value.is_a?(FalseClass)
179
+ end
180
+
181
+ test 'accepted_values options' do
182
+ Setting.settings do
183
+ some_super_option :default => 0, :accepted_values => 0..3
184
+ string_super_option :default => "en", :accepted_values => ['ru','en','by']
185
+ end
186
+
187
+ assert_raise Exception do
188
+ Setting.some_super_option = 4
189
+ end
190
+ assert (Setting.some_super_option = 1) && (Setting.some_super_option == 1)
191
+
192
+ assert_raise Exception do
193
+ Setting.string_super_option = 'us'
194
+ end
195
+ assert Setting.string_super_option = 'ru'
196
+ end
197
+
198
+ test "regexp accepted values" do
199
+ Setting.settings do
200
+ some_option :default => 0, :accepted_values => /abc/
201
+ end
202
+
203
+ assert Setting.some_option = 'abc'
204
+ assert_raise Exception do
205
+ Setting.some_option = 'abd'
206
+ end
207
+ end
208
+
209
+ test 'namespaces get' do
210
+ Setting.settings :view do
211
+ nested_number :default => 10
212
+ end
213
+
214
+ assert Setting.view.is_a? SettingsLord::Reflector
215
+ assert Setting.view.nested_number == 10
216
+ end
217
+
218
+ test 'namespace set' do
219
+ Setting.settings :view do
220
+ nested_number :default => 10
221
+ end
222
+
223
+ Setting.view.nested_number = 20
224
+ assert Setting.view.nested_number == 20
225
+ end
226
+ end
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_support'
4
+ require 'active_record'
5
+
6
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:", :database => 'settings_test')
7
+
8
+ ActiveRecord::Schema.define(:version => 1) do
9
+ create_table :settings, :force => true do |t|
10
+ t.string :name
11
+ t.text :value
12
+ t.string :klass
13
+ t.integer :parent_id
14
+ end
15
+ end
16
+
17
+ class Setting < ActiveRecord::Base
18
+ end
19
+
20
+ require File.join(File.dirname(__FILE__),'..','lib','settings_lord.rb')
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: settings_lord
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.0.1
6
+ platform: ruby
7
+ authors:
8
+ - pechrorin_andrey
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-06-30 00:00:00 +04:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Best way to manage your site settings
18
+ email:
19
+ - pechorin.andrey@gmail.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - MIT-LICENSE
28
+ - README.md
29
+ - Rakefile
30
+ - lib/generators/settings_lord/settings_lord_generator.rb
31
+ - lib/generators/settings_lord/templates/migration.rb
32
+ - lib/generators/settings_lord/templates/setting.rb
33
+ - lib/settings_lord.rb
34
+ - lib/settings_lord/active_record.rb
35
+ - lib/settings_lord/base.rb
36
+ - lib/settings_lord/meta_setting.rb
37
+ - lib/settings_lord/meta_setting_collection.rb
38
+ - lib/settings_lord/reflector.rb
39
+ - lib/settings_lord/setting_creator.rb
40
+ - lib/settings_lord/version.rb
41
+ - settings_lord.gemspec
42
+ - test/settings_lord_test.rb
43
+ - test/test_helper.rb
44
+ has_rdoc: true
45
+ homepage: https://github.com/pechorin/settings_lord
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.6.2
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Best way to manage your site settings
72
+ test_files:
73
+ - test/settings_lord_test.rb
74
+ - test/test_helper.rb