settingsdb-rails 1.0.5

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.
Files changed (68) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +43 -0
  3. data/Rakefile +40 -0
  4. data/lib/generators/settingsdb/USAGE +8 -0
  5. data/lib/generators/settingsdb/install_generator.rb +103 -0
  6. data/lib/generators/settingsdb/templates/initializer.rb +3 -0
  7. data/lib/generators/settingsdb/templates/migration.rb +18 -0
  8. data/lib/generators/settingsdb/templates/migration_exists.rb +10 -0
  9. data/lib/settingsdb-rails.rb +6 -0
  10. data/lib/settingsdb/acts_as_setting.rb +48 -0
  11. data/lib/settingsdb/defaults.rb +91 -0
  12. data/lib/settingsdb/generators/generated_attribute.rb +104 -0
  13. data/lib/settingsdb/settings.rb +121 -0
  14. data/lib/settingsdb/version.rb +3 -0
  15. data/test/acts_as_setting_test.rb +90 -0
  16. data/test/dummy/Rakefile +7 -0
  17. data/test/dummy/app/assets/javascripts/application.js +9 -0
  18. data/test/dummy/app/assets/stylesheets/application.css +7 -0
  19. data/test/dummy/app/controllers/application_controller.rb +3 -0
  20. data/test/dummy/app/helpers/application_helper.rb +2 -0
  21. data/test/dummy/app/models/config_a.rb +3 -0
  22. data/test/dummy/app/models/config_b.rb +3 -0
  23. data/test/dummy/app/models/test_setting.rb +3 -0
  24. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  25. data/test/dummy/config.ru +4 -0
  26. data/test/dummy/config/application.rb +45 -0
  27. data/test/dummy/config/boot.rb +10 -0
  28. data/test/dummy/config/database.yml +25 -0
  29. data/test/dummy/config/environment.rb +5 -0
  30. data/test/dummy/config/environments/development.rb +30 -0
  31. data/test/dummy/config/environments/production.rb +60 -0
  32. data/test/dummy/config/environments/test.rb +39 -0
  33. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  34. data/test/dummy/config/initializers/inflections.rb +10 -0
  35. data/test/dummy/config/initializers/mime_types.rb +5 -0
  36. data/test/dummy/config/initializers/secret_token.rb +7 -0
  37. data/test/dummy/config/initializers/session_store.rb +8 -0
  38. data/test/dummy/config/initializers/settingsdb.rb +3 -0
  39. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  40. data/test/dummy/config/locales/en.yml +5 -0
  41. data/test/dummy/config/routes.rb +58 -0
  42. data/test/dummy/db/development.sqlite3 +0 -0
  43. data/test/dummy/db/migrate/20120327011030_settingsdb_create_test_settings.rb +12 -0
  44. data/test/dummy/db/migrate/20120327011127_settingsdb_create_config_as.rb +12 -0
  45. data/test/dummy/db/migrate/20120327011134_settingsdb_create_config_bs.rb +12 -0
  46. data/test/dummy/db/schema.rb +43 -0
  47. data/test/dummy/db/test.sqlite3 +0 -0
  48. data/test/dummy/log/development.log +512 -0
  49. data/test/dummy/log/test.log +3749 -0
  50. data/test/dummy/public/404.html +26 -0
  51. data/test/dummy/public/422.html +26 -0
  52. data/test/dummy/public/500.html +26 -0
  53. data/test/dummy/public/favicon.ico +0 -0
  54. data/test/dummy/script/rails +6 -0
  55. data/test/dummy/test/fixtures/config_as.yml +11 -0
  56. data/test/dummy/test/fixtures/config_bs.yml +11 -0
  57. data/test/dummy/test/fixtures/configurations.yml +11 -0
  58. data/test/dummy/test/fixtures/settings.yml +11 -0
  59. data/test/dummy/test/fixtures/test_settings.yml +11 -0
  60. data/test/dummy/test/unit/config_a_test.rb +7 -0
  61. data/test/dummy/test/unit/config_b_test.rb +7 -0
  62. data/test/dummy/test/unit/configuration_test.rb +7 -0
  63. data/test/dummy/test/unit/setting_test.rb +7 -0
  64. data/test/dummy/test/unit/test_setting_test.rb +7 -0
  65. data/test/settingsdb_defaults_test.rb +71 -0
  66. data/test/settingsdb_generator_test.rb +42 -0
  67. data/test/test_helper.rb +10 -0
  68. metadata +215 -0
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
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.
@@ -0,0 +1,43 @@
1
+ = SettingsDB-Rails
2
+
3
+ SettingsDB provides an easy to use mechanism for keeping application settings
4
+ in your database. It also provides a namespacing mechanism to keep settings
5
+ from different areas separate, as well as a defaults option.
6
+
7
+ == Getting Started
8
+
9
+ Add settingsdb-rails to your Gemfile:
10
+
11
+ gem 'settingsdb-rails'
12
+
13
+ To install the model, migration, and defaults initializer:
14
+
15
+ rails generate settingsdb:install
16
+ rake db:migrate
17
+
18
+ This will create a `settings` model, migration, and initializer file.
19
+ Now just reference settings in your code:
20
+
21
+ <% title Setting[:site_title] %>
22
+
23
+ To create a new setting just set its value:
24
+
25
+ Setting[:site_title] = "My Awesome Site!"
26
+
27
+ Non-qualified key operations use the `:default` namespace, to set a key
28
+ in a particular namespace:
29
+
30
+ Setting[:myplugin, :site_title] = "My Awesome Plugin Site!"
31
+
32
+ To set application defaults, use `SettingsDB::Defaults`:
33
+
34
+ SettingsDB::Defaults[:site_title] = 'Untitled'
35
+ SettingsDB::Defaults[:myplugin, :site_title] = 'Untitled Plugin'
36
+
37
+ Or use a block:
38
+
39
+ SettingsDB::Defaults.config do |c|
40
+ c[:site_title] = 'Untitled'
41
+ c[:myplugin, :site_title] = 'Untitled Plugin'
42
+ end
43
+
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
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
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'SettingsDB-Rails'
18
+ rdoc.main = 'README.rdoc'
19
+ rdoc.options << '--line-numbers'
20
+ rdoc.rdoc_files.include('README.rdoc')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ rdoc.rdoc_files.exclude('lib/settingsdb-rails.rb', 'lib/settingsdb/version.rb')
23
+ rdoc.rdoc_files.exclude('lib/generators/**/*')
24
+ end
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate settingsdb Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,103 @@
1
+ require 'rails/generators/named_base'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record/migration'
4
+ require 'active_record'
5
+ require 'settingsdb/generators/generated_attribute'
6
+
7
+ module SettingsDB::Generators # :nodoc: all
8
+ class InstallGenerator < Rails::Generators::NamedBase
9
+ include Rails::Generators::Migration
10
+ extend ActiveRecord::Generators::Migration
11
+
12
+ namespace "settingsdb:install"
13
+ argument :name, :type => :string, :default => 'settings'
14
+ argument :attributes, :type => :array, :default => [], :banner => "field:type[[:index][:default]] ..."
15
+ source_root File.expand_path('../templates', __FILE__)
16
+
17
+
18
+ desc "Creates a SettingsDB initializer, Model, and Migration"
19
+ class_option :model, :desc => 'Generate the model', :type => :boolean, :default => true
20
+ class_option :migration, :desc => 'Generate the migration', :type => :boolean, :default => true
21
+
22
+ def add_settingsdb_model
23
+ return if !options.model? || model_exists?
24
+ invoke 'active_record:model', [name.singularize], :migration => false
25
+ end
26
+
27
+ def inject_settingsdb_content
28
+ return if !options.model?
29
+ inject_into_class(model_path, model_class, " acts_as_setting\n")
30
+ end
31
+
32
+ def add_settingsdb_migration
33
+ return if !options.migration?
34
+ if migration_exists?
35
+ migration_template 'migration_exists.rb', "db/migrate/settingsdb_add_settings_columns_to_#{table_name}"
36
+ else
37
+ migration_template 'migration.rb', "db/migrate/settingsdb_create_#{table_name}"
38
+ end
39
+ end
40
+
41
+ def add_settingsdb_initializer
42
+ return if initializer_exists?
43
+ template 'initializer.rb', 'config/initializers/settingsdb.rb'
44
+ end
45
+
46
+ protected
47
+ # override Rails::Generators::NamedBase#parse_attributes! to customize attribute parsing
48
+ def parse_attributes!
49
+ self.attributes = (attributes || []).map do |key_value|
50
+ name, type, index, default = key_value.split(/:/)
51
+ opts = {}
52
+ if default
53
+ opts[:default] = default
54
+ end
55
+ if index
56
+ index_type, constraint = index.split(/,/)
57
+ if constraint == 'not_null'
58
+ opts[:null] = false
59
+ end
60
+ end
61
+ create_attribute(name, type, index_type, opts)
62
+ end
63
+ end
64
+
65
+ def create_attribute(*args)
66
+ if Rails.version[0,3].to_f >= 3.2
67
+ Rails::Generators::GeneratedAttribute.new(*args)
68
+ else
69
+ SettingsDB::Generators::GeneratedAttribute.new(*args)
70
+ end
71
+ end
72
+
73
+ # Helper methods shamelessly copied from Devise
74
+ def file_name
75
+ name.underscore
76
+ end
77
+
78
+ def model_class
79
+ class_name.singularize
80
+ end
81
+
82
+ def model_path
83
+ @model_path ||= File.join('app', 'models', class_path, "#{file_name.singularize}.rb")
84
+ end
85
+
86
+ def migration_path
87
+ @migration_path ||= File.join("db", "migrate")
88
+ end
89
+
90
+ def model_exists?
91
+ File.exists?(File.join(destination_root, model_path))
92
+ end
93
+
94
+ def migration_exists?
95
+ Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/settingsdb_create_#{table_name}.rb$/).first
96
+ end
97
+
98
+ def initializer_exists?
99
+ File.exists?(File.join(destination_root, File.join(%w(config initializers settingsdb.rb))))
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ SettingsDB::Defaults.config do |config|
2
+ #config[:setting] = :value
3
+ end
@@ -0,0 +1,18 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration
2
+ def change
3
+ create_table :<%= table_name %> do |t|
4
+ t.string :namespace, :null => false, :default => 'default'
5
+ t.string :name, :null => false
6
+ t.text :value
7
+ <% attributes.each do |attr| -%>
8
+ t.<%= attr.type %> :<%= attr.name %><%= attr.inject_options %>
9
+ <% end -%>
10
+ end
11
+
12
+ add_index :<%= table_name %>, [:namespace, :name], :unique => true
13
+ add_index :<%= table_name %>, :name
14
+ <% attributes.reject {|attr| !attr.has_index?}.each do |attr| -%>
15
+ add_index :<%= table_name %>, :<%= attr.name %><%= attr.inject_index_options %>
16
+ <% end -%>
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration
2
+ def change
3
+ add_column :<%= table_name %>, :namespace, :string, :null => false, :default => 'default'
4
+ add_column :<%= table_name %>, :name, :string, :null => false
5
+ add_column :<%= table_name %>, :value, :text
6
+
7
+ add_index :<%= table_name %>, [:namespace, :name], :unique => true
8
+ add_index :<%= table_name %>, :name
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module SettingsDB # :nodoc:
2
+ end
3
+
4
+ require 'settingsdb/defaults'
5
+ require 'settingsdb/settings'
6
+ require 'settingsdb/acts_as_setting'
@@ -0,0 +1,48 @@
1
+ module SettingsDB::ActsAsSetting # :nodoc:
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ end
6
+
7
+ module ClassMethods
8
+ ##
9
+ # This method causes the model to import the SettingsDB behavior
10
+ # A SettingsDB enabled modle requires 3 fields: name, namespace, and value
11
+ # This method also takes options to override the default names of these fields.
12
+ # === Options
13
+ # *:setting_namespace_field*:: Override namespace field-name (default: +:namespace+)
14
+ # *:setting_name_field*:: Override name field-name (default: +:name+)
15
+ # *:setting_value_field*:: Override value field-name (default: +:value+)
16
+ #
17
+ # === Examples
18
+ #
19
+ # To use the default field names in your model, no options are needed:
20
+ #
21
+ # class Setting < ActiveRecord::Base
22
+ # acts_as_setting
23
+ # end
24
+ #
25
+ # If your model needs to rename a setting field's name pass them as options
26
+ # to +acts_as_settings+. Here the +Configuration+ model keeps the namespace
27
+ # value in the +:scope+ field, and the setting name value in the +:key+ field:
28
+ #
29
+ # class Configuration < ActiveRecord::Base
30
+ # acts_as_setting :setting_namespace_field => :scope, :setting_name_field => :key
31
+ # end
32
+ #
33
+ def acts_as_setting(options = {})
34
+ cattr_accessor :setting_namespace_field, :setting_name_field, :setting_value_field
35
+ self.setting_name_field = (options[:setting_name_field] || :name).to_sym
36
+ self.setting_namespace_field = (options[:setting_namespace_field] || :namespace).to_sym
37
+ self.setting_value_field = (options[:setting_value_field] || :value).to_sym
38
+ class_eval(<<-BLOCK, __FILE__, __LINE__ + 1)
39
+ include SettingsDB::Settings
40
+ serialize :#{setting_value_field}
41
+ before_destroy :remove_from_cache
42
+
43
+ BLOCK
44
+ end
45
+ end
46
+ end
47
+
48
+ ActiveRecord::Base.send :include, SettingsDB::ActsAsSetting
@@ -0,0 +1,91 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ class SettingsDB::Defaults
3
+
4
+ ##
5
+ # :call-seq:
6
+ # Defaults[:key] -> value (from :default namespace)
7
+ # Defaults[:p1, :key] -> value (from :p1 namespace)
8
+ #
9
+ # Returns the value for the index. If namespace is given
10
+ # returns the value for the index in that namespace.
11
+ # When no namespace is given, the :default namespace is used.
12
+ def self.[](namespace = :default, index)
13
+ @@defaults[namespace][index] if @@defaults[namespace]
14
+ end
15
+
16
+ ##
17
+ # :call-seq:
18
+ # Defaults[:key] = value -> 'value' (in :default namespace)
19
+ # Defaults[:p1, :key] = value -> 'value' (in :p1 namespace)
20
+ #
21
+ # Sets the value for the index.
22
+ # If a namespace is given then the index is set in that namespace
23
+ # else it is set in the default namespace.
24
+ def self.[]=(namespace = :default, index, value)
25
+ if @@defaults[namespace] && @@defaults[namespace].has_key?(index)
26
+ @@defaults[namespace][index] = value
27
+ else
28
+ @@defaults[namespace] = { index => value }
29
+ value
30
+ end
31
+ end
32
+
33
+ ##
34
+ # :call-seq:
35
+ # Defaults.config -> hash
36
+ # Defaults.config {|config| ...}
37
+ #
38
+ # If given a block yields self. If no block is given
39
+ # the hash of default values is returned.
40
+ # === Example
41
+ # Defaults.config do |conf|
42
+ # conf[:key1] = value1
43
+ # conf[:ns1, :key1] = value2
44
+ # end
45
+ #
46
+ # If no block is given the default hash is returned and
47
+ # can be manipulated directly:
48
+ #
49
+ # default_hash = Defaults.config
50
+ # default_hash[:default][:key1] = value1
51
+ # default_hash[:ns1] = { :key1 => value2 }
52
+ def self.config # :yields: config
53
+ if block_given?
54
+ yield self
55
+ end
56
+ self
57
+ end
58
+
59
+ ##
60
+ # :call-seq:
61
+ # reset! -> Defaults
62
+ #
63
+ # Deletes all the default settings.
64
+ def self.reset!
65
+ @@defaults = { :default => {} }.with_indifferent_access
66
+ self
67
+ end
68
+
69
+ ##
70
+ # :call-seq:
71
+ # defaults! -> hash
72
+ #
73
+ # Returns the actual reference to the internal defaults hash.
74
+ # USE THIS WITH CARE!
75
+ def self.defaults!
76
+ @@defaults
77
+ end
78
+
79
+ ##
80
+ # :call-seq:
81
+ # defaults -> hash
82
+ #
83
+ # Returns a deep copy of the defaults hash, modifying this will
84
+ # have no impact on Defaults[] results.
85
+ def self.defaults
86
+ # Do a deep copy
87
+ Marshal.load(Marshal.dump(@@defaults))
88
+ end
89
+
90
+ reset!
91
+ end
@@ -0,0 +1,104 @@
1
+ # This was copied from rails 3.2 to extend the support to earlier rails versions
2
+ require 'active_support/time'
3
+ require 'active_support/core_ext/object/inclusion'
4
+ require 'active_support/core_ext/object/blank'
5
+
6
+ module SettingsDB::Generators # :nodoc: all
7
+ class GeneratedAttribute
8
+ attr_accessor :name, :type
9
+ attr_reader :attr_options
10
+
11
+ class << self
12
+ def parse(column_definition)
13
+ name, type, has_index = column_definition.split(':')
14
+
15
+ # if user provided "name:index" instead of "name:string:index"
16
+ # type should be set blank so GeneratedAttribute's constructor
17
+ # could set it to :string
18
+ has_index, type = type, nil if %w(index uniq).include?(type)
19
+
20
+ type, attr_options = *parse_type_and_options(type)
21
+ new(name, type, has_index, attr_options)
22
+ end
23
+
24
+ private
25
+
26
+ # parse possible attribute options like :limit for string/text/binary/integer or :precision/:scale for decimals
27
+ # when declaring options curly brackets should be used
28
+ def parse_type_and_options(type)
29
+ case type
30
+ when /(string|text|binary|integer){(\d+)}/
31
+ return $1, :limit => $2.to_i
32
+ when /decimal{(\d+),(\d+)}/
33
+ return :decimal, :precision => $1.to_i, :scale => $2.to_i
34
+ else
35
+ return type, {}
36
+ end
37
+ end
38
+ end
39
+
40
+ def initialize(name, type=nil, index_type=false, attr_options={})
41
+ @name = name
42
+ @type = (type.presence || :string).to_sym
43
+ @has_index = %w(index uniq).include?(index_type)
44
+ @has_uniq_index = %w(uniq).include?(index_type)
45
+ @attr_options = attr_options
46
+ end
47
+
48
+ def field_type
49
+ @field_type ||= case type
50
+ when :integer then :number_field
51
+ when :float, :decimal then :text_field
52
+ when :time then :time_select
53
+ when :datetime, :timestamp then :datetime_select
54
+ when :date then :date_select
55
+ when :text then :text_area
56
+ when :boolean then :check_box
57
+ else :text_field
58
+ end
59
+ end
60
+
61
+ def default
62
+ @default ||= case type
63
+ when :integer then 1
64
+ when :float then 1.5
65
+ when :decimal then "9.99"
66
+ when :datetime, :timestamp, :time then Time.now.to_s(:db)
67
+ when :date then Date.today.to_s(:db)
68
+ when :string then name == "type" ? "" : "MyString"
69
+ when :text then "MyText"
70
+ when :boolean then false
71
+ when :references, :belongs_to then nil
72
+ else ""
73
+ end
74
+ end
75
+
76
+ def human_name
77
+ name.to_s.humanize
78
+ end
79
+
80
+ def index_name
81
+ reference? ? "#{name}_id" : name
82
+ end
83
+
84
+ def reference?
85
+ self.type.in?([:references, :belongs_to])
86
+ end
87
+
88
+ def has_index?
89
+ @has_index
90
+ end
91
+
92
+ def has_uniq_index?
93
+ @has_uniq_index
94
+ end
95
+
96
+ def inject_options
97
+ @attr_options.blank? ? '' : ", #{@attr_options.to_s.gsub(/[{}]/, '')}"
98
+ end
99
+
100
+ def inject_index_options
101
+ has_uniq_index? ? ", :unique => true" : ''
102
+ end
103
+ end
104
+ end