ruby-settings-cached 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ba4e9ee304a2b3dad3de28b7991da2385eb5f3e9
4
+ data.tar.gz: 034bf0a2d72024d4ed6762ae83a753bb27ec9c52
5
+ SHA512:
6
+ metadata.gz: 5047728194298915cb178c2a93c7e1bb3d81375a905b152f8399cb87476d2458eb06e50d721850f92888b344d90dda492a508b2e6f66f211d0e4f03bd1e05194
7
+ data.tar.gz: 125508ee57f87528a0c3a3c49be8f0b049c1656983f62b6d2985a448a15d96c58ce02bb1dbfcb404970a9c84b2ce7919f470d0ca974f44725c167ee547d13e50
data/README.md ADDED
@@ -0,0 +1,189 @@
1
+ # Settings Gem
2
+
3
+ This is improved from [rails-settings](https://github.com/ledermann/rails-settings),
4
+ added caching for all settings. Settings is a plugin that makes managing a table of
5
+ global key, value pairs easy. Think of it like a global Hash stored in your database,
6
+ that uses simple ActiveRecord like methods for manipulation. Keep track of any global
7
+ setting that you dont want to hard code into your rails app. You can store any kind
8
+ of object. Strings, numbers, arrays, or any object.
9
+
10
+ ## Status
11
+
12
+ - [![Gem Version](https://badge.fury.io/rb/rails-settings-cached.png)](https://rubygems.org/gems/rails-settings-cached)
13
+ - [![CI Status](https://travis-ci.org/RobotJiang/ruby-settings-cached.svg)](https://travis-ci.org/RobotJiang/ruby-settings-cached)
14
+
15
+ ## Setup
16
+
17
+ Edit your Gemfile:
18
+
19
+ ```ruby
20
+ # Rails 4+ project or Only ruby project
21
+ gem "ruby-settings-cached", "0.1"
22
+ ```
23
+
24
+ Generate your settings if you use Rails:
25
+
26
+ ```bash
27
+ $ rails g settings <settings_name>
28
+ ```
29
+
30
+ ```
31
+
32
+ Now just put that migration in the database with:
33
+
34
+ ```bash
35
+ rake db:migrate
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ The syntax is easy. First, lets create some settings to keep track of:
41
+
42
+ ```ruby
43
+ Setting.admin_password = 'supersecret'
44
+ Setting.date_format = '%m %d, %Y'
45
+ Setting.cocktails = ['Martini', 'Screwdriver', 'White Russian']
46
+ Setting.foo = 123
47
+ Setting.credentials = { :username => 'tom', :password => 'secret' }
48
+ ```
49
+
50
+ Now lets read them back:
51
+
52
+ ```ruby
53
+ Setting.foo # returns 123
54
+ ```
55
+
56
+ Changing an existing setting is the same as creating a new setting:
57
+
58
+ ```ruby
59
+ Setting.foo = 'super duper bar'
60
+ ```
61
+
62
+ For changing an existing setting which is a Hash, you can merge new values with existing ones:
63
+
64
+ ```ruby
65
+ Setting.merge!(:credentials, :password => 'topsecret')
66
+ Setting.credentials # returns { :username => 'tom', :password => 'topsecret' }
67
+ ```
68
+
69
+ Decide you dont want to track a particular setting anymore?
70
+
71
+ ```ruby
72
+ Setting.destroy :foo
73
+ Setting.foo # returns nil
74
+ ```
75
+
76
+ Want a list of all the settings?
77
+ ```ruby
78
+ # Rails 4.1.x
79
+ Setting.get_all
80
+ # Rails 3.x and 4.0.x
81
+ Setting.all
82
+ # returns {'admin_password' => 'super_secret', 'date_format' => '%m %d, %Y'}
83
+ ```
84
+
85
+ You need name spaces and want a list of settings for a give name space? Just choose your prefered named space delimiter and use `Setting.get_all` (`Settings.all` for # Rails 3.x and 4.0.x) like this:
86
+
87
+ ```ruby
88
+ Setting['preferences.color'] = :blue
89
+ Setting['preferences.size'] = :large
90
+ Setting['license.key'] = 'ABC-DEF'
91
+ # Rails 4.1.x
92
+ Setting.get_all('preferences.')
93
+ # Rails 3.x and 4.0.x
94
+ Setting.all('preferences.')
95
+ # returns { 'preferences.color' => :blue, 'preferences.size' => :large }
96
+ ```
97
+
98
+ Set defaults for certain settings of your app. This will cause the defined settings to return with the
99
+ Specified value even if they are **not in the database**. Make a new file in `config/initializers/default_settings.rb`
100
+ with the following:
101
+
102
+ ```ruby
103
+ Setting.defaults[:some_setting] = 'footastic'
104
+ Setting.where(:var => "some_setting").count
105
+ => 0
106
+ Setting.some_setting
107
+ => "footastic"
108
+ ```
109
+
110
+ Init default value in database, this has indifferent with `Setting.defaults[:some_setting]`, this will **save the value into database**:
111
+
112
+ ```ruby
113
+ Setting.save_default(:some_key, "123")
114
+ Setting.where(:var => "some_key").count
115
+ => 1
116
+ Setting.some_key
117
+ => "123"
118
+ ```
119
+
120
+ Settings may be bound to any existing ActiveRecord object. Define this association like this:
121
+ Notice! is not do caching in this version.
122
+
123
+ ```ruby
124
+ class User < ActiveRecord::Base
125
+ include RailsSettings::Extend
126
+ end
127
+ ```
128
+
129
+ Then you can set/get a setting for a given user instance just by doing this:
130
+
131
+ ```ruby
132
+ user = User.find(123)
133
+ user.settings.color = :red
134
+ user.settings.color # returns :red
135
+ # Rails 4.1.x
136
+ user.settings.get_all
137
+ # Rails 3.x and 4.0.x
138
+ user.settings.all
139
+ # { "color" => :red }
140
+ ```
141
+
142
+ If you want to find users having or not having some settings, there are named scopes for this:
143
+
144
+ ```ruby
145
+ User.with_settings
146
+ # => returns a scope of users having any setting
147
+
148
+ User.with_settings_for('color')
149
+ # => returns a scope of users having a 'color' setting
150
+
151
+ User.without_settings
152
+ # returns a scope of users having no setting at all (means user.settings.get_all == {})
153
+
154
+ User.without_settings('color')
155
+ # returns a scope of users having no 'color' setting (means user.settings.color == nil)
156
+ ```
157
+
158
+ Settings maybe dynamically scoped. For example, if you're using [apartment gem](https://github.com/influitive/apartment) for multitenancy, you may not want tenants to share settings:
159
+
160
+ ```ruby
161
+ class Settings < RailsSettings::CachedSettings
162
+ cache_prefix { Apartment::Tenant.current }
163
+ ...
164
+ end
165
+ ```
166
+
167
+ -----
168
+
169
+ ## How to create a list, form to manage Settings?
170
+
171
+ If you want create an admin interface to editing the Settings, you can try methods in follow:
172
+
173
+ ```ruby
174
+ class SettingsController < ApplicationController
175
+ def index
176
+ # to get all items for render list
177
+ @settings = Setting.unscoped
178
+ end
179
+
180
+ def edit
181
+ @setting = Setting.unscoped.find(params[:id])
182
+ end
183
+ end
184
+ ```
185
+
186
+
187
+ Also you may use [rails-settings-ui](https://github.com/accessd/rails-settings-ui) gem
188
+ for building ready to using interface with validations.
189
+
@@ -0,0 +1,32 @@
1
+ require 'rails/generators/migration'
2
+
3
+ if defined?(Rails)
4
+ class SettingsGenerator < Rails::Generators::NamedBase
5
+ include Rails::Generators::Migration
6
+
7
+ argument :name, type: :string, default: 'my_settings'
8
+
9
+ source_root File.expand_path('../templates', __FILE__)
10
+
11
+ @@migrations = false
12
+
13
+ def self.next_migration_number(dirname) #:nodoc:
14
+ if ActiveRecord::Base.timestamped_migrations
15
+ if @@migrations
16
+ (current_migration_number(dirname) + 1)
17
+ else
18
+ @@migrations = true
19
+ Time.now.utc.strftime('%Y%m%d%H%M%S')
20
+ end
21
+ else
22
+ format '%.3d', current_migration_number(dirname) + 1
23
+ end
24
+ end
25
+
26
+ def settings
27
+ # generate(:model, name, "--skip-migration")
28
+ template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb"), force: true
29
+ migration_template 'migration.rb', 'db/migrate/create_settings.rb'
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ class CreateSettings < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :settings do |t|
4
+ t.string :var, null: false
5
+ t.text :value, null: true
6
+ t.integer :thing_id, null: true
7
+ t.string :thing_type, null: true, limit: 30
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :settings, %i(thing_type thing_id var), unique: true
12
+ end
13
+
14
+ def self.down
15
+ drop_table :settings
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ # RubySettings Model
2
+ class <%= class_name %> < RubySettings::CachedSettings
3
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'ruby-settings/settings'
2
+ require_relative 'ruby-settings/configuration'
3
+ require_relative 'ruby-settings/cached_settings'
4
+ require_relative 'ruby-settings/scoped_settings'
5
+ require_relative 'ruby-settings/extend'
6
+
7
+
@@ -0,0 +1,51 @@
1
+ module RubySettings
2
+ class CachedSettings < Settings
3
+ after_update :rewrite_cache
4
+ after_create :rewrite_cache
5
+ after_destroy :expire_cache
6
+
7
+ include RubySettings::ConfigurationHelpers
8
+
9
+ def rewrite_cache
10
+ cache_store.write(cache_key, value)
11
+ end
12
+
13
+ def expire_cache
14
+ cache_store.delete(cache_key)
15
+ end
16
+
17
+ def cache_key
18
+ self.class.cache_key(var, thing)
19
+ end
20
+
21
+ class << self
22
+ def cache_prefix(&block)
23
+ @cache_prefix = block
24
+ end
25
+
26
+ def cache_key(var_name, scope_object)
27
+ scope = "rails_settings_cached:"
28
+ scope << "#{@cache_prefix.call}:" if @cache_prefix
29
+ scope << "#{scope_object.class.name}-#{scope_object.id}:" if scope_object
30
+ scope << "#{var_name}"
31
+ end
32
+
33
+ def [](var_name)
34
+ value = RubySettings.config.cache_store.fetch(cache_key(var_name, @object)) do
35
+ super(var_name)
36
+ end
37
+
38
+ if value.nil?
39
+ @@defaults[var_name.to_s] if value.nil?
40
+ else
41
+ value
42
+ end
43
+ end
44
+
45
+ def save_default(key, value)
46
+ return false unless self[key].nil?
47
+ self[key] = value
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,30 @@
1
+ module RubySettings
2
+
3
+ class << self
4
+
5
+ attr_accessor :configuration
6
+
7
+ def config
8
+ self.configuration ||= Configuration.new
9
+ end
10
+
11
+ def configure
12
+ yield config if block_given?
13
+ end
14
+
15
+ end
16
+
17
+ class Configuration
18
+ attr_accessor :cache_store
19
+ end
20
+
21
+ module ConfigurationHelpers
22
+ extend ActiveSupport::Concern
23
+
24
+ def cache_store
25
+ @cache_store ||= (RubySettings.config.cache_store || ActiveSupport::Cache::MemoryStore.new)
26
+ end
27
+
28
+ end
29
+ end
30
+
@@ -0,0 +1,34 @@
1
+ module RubySettings
2
+ module Extend
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ scope :with_settings, lambda {
7
+ joins("JOIN settings ON (settings.thing_id = #{table_name}.#{primary_key} AND
8
+ settings.thing_type = '#{base_class.name}')")
9
+ .select("DISTINCT #{table_name}.*")
10
+ }
11
+
12
+ scope :with_settings_for, lambda { |var|
13
+ joins("JOIN settings ON (settings.thing_id = #{table_name}.#{primary_key} AND
14
+ settings.thing_type = '#{base_class.name}') AND settings.var = '#{var}'")
15
+ }
16
+
17
+ scope :without_settings, lambda {
18
+ joins("LEFT JOIN settings ON (settings.thing_id = #{table_name}.#{primary_key} AND
19
+ settings.thing_type = '#{base_class.name}')")
20
+ .where('settings.id IS NULL')
21
+ }
22
+
23
+ scope :without_settings_for, lambda { |var|
24
+ where('settings.id IS NULL')
25
+ .joins("LEFT JOIN settings ON (settings.thing_id = #{table_name}.#{primary_key} AND
26
+ settings.thing_type = '#{base_class.name}') AND settings.var = '#{var}'")
27
+ }
28
+ end
29
+
30
+ def settings
31
+ ScopedSettings.for_thing(self)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ module RubySettings
2
+ class ScopedSettings < CachedSettings
3
+ def self.for_thing(object)
4
+ @object = object
5
+ self
6
+ end
7
+
8
+ def self.thing_scoped
9
+ unscoped.where(thing_type: @object.class.base_class.to_s, thing_id: @object.id)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,110 @@
1
+ module RubySettings
2
+ class Settings < ActiveRecord::Base
3
+ self.table_name = table_name_prefix + 'settings'
4
+
5
+ class SettingNotFound < RuntimeError; end
6
+
7
+ cattr_accessor :defaults
8
+ @@defaults = {}.with_indifferent_access
9
+
10
+ belongs_to :thing, polymorphic: true
11
+
12
+ # Support old plugin
13
+ if defined?(SettingsDefaults::DEFAULTS)
14
+ @@defaults = SettingsDefaults::DEFAULTS.with_indifferent_access
15
+ end
16
+
17
+ # get the value field, YAML decoded
18
+ def value
19
+ YAML.load(self[:value])
20
+ end
21
+
22
+ # set the value field, YAML encoded
23
+ def value=(new_value)
24
+ self[:value] = new_value.to_yaml
25
+ end
26
+
27
+ class << self
28
+ # get or set a variable with the variable as the called method
29
+ def method_missing(method, *args)
30
+ method_name = method.to_s
31
+ super(method, *args)
32
+ rescue NoMethodError
33
+ # set a value for a variable
34
+ if method_name[-1] == '='
35
+ var_name = method_name.sub('=', '')
36
+ value = args.first
37
+ self[var_name] = value
38
+ else
39
+ # retrieve a value
40
+ self[method_name]
41
+ end
42
+ end
43
+
44
+ # destroy the specified settings record
45
+ def destroy(var_name)
46
+ var_name = var_name.to_s
47
+ obj = object(var_name)
48
+ raise SettingNotFound, "Setting variable \"#{var_name}\" not found" if obj.nil?
49
+
50
+ obj.destroy
51
+ true
52
+ end
53
+
54
+ # retrieve all settings as a hash (optionally starting with a given namespace)
55
+ def get_all(starting_with = nil)
56
+ vars = thing_scoped.select('var, value')
57
+ vars = vars.where("var LIKE '#{starting_with}%'") if starting_with
58
+
59
+ result = {}
60
+ vars.each do |record|
61
+ result[record.var] = record.value
62
+ end
63
+ result.merge! @@defaults.slice(*(@@defaults.keys - result.keys))
64
+
65
+ result.with_indifferent_access
66
+ end
67
+
68
+ def where(sql = nil)
69
+ vars = thing_scoped.where(sql) if sql
70
+ vars
71
+ end
72
+
73
+ # get a setting value by [] notation
74
+ def [](var_name)
75
+ object(var_name).try(:value) || @@defaults[var_name.to_s]
76
+ end
77
+
78
+ # set a setting value by [] notation
79
+ def []=(var_name, value)
80
+ var_name = var_name.to_s
81
+
82
+ record = object(var_name) || thing_scoped.new(var: var_name)
83
+ record.value = value
84
+ record.save!
85
+
86
+ value
87
+ end
88
+
89
+ def merge!(var_name, hash_value)
90
+ raise ArgumentError unless hash_value.is_a?(Hash)
91
+
92
+ old_value = self[var_name] || {}
93
+ raise TypeError, "Existing value is not a hash, can't merge!" unless old_value.is_a?(Hash)
94
+
95
+ new_value = old_value.merge(hash_value)
96
+ self[var_name] = new_value if new_value != old_value
97
+
98
+ new_value
99
+ end
100
+
101
+ def object(var_name)
102
+ thing_scoped.where(var: var_name.to_s).first
103
+ end
104
+
105
+ def thing_scoped
106
+ unscoped.where('thing_type is NULL and thing_id is NULL')
107
+ end
108
+ end
109
+ end
110
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-settings-cached
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Squeegy
8
+ - Georg Ledermann
9
+ - 100hz
10
+ - Jason Lee
11
+ - Raymond Jiang
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+ date: 2015-12-15 00:00:00.000000000 Z
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: activerecord
19
+ requirement: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 4.2.0
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: 4.2.0
31
+ - !ruby/object:Gem::Dependency
32
+ name: activesupport
33
+ requirement: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 4.2.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 4.2.0
45
+ - !ruby/object:Gem::Dependency
46
+ name: rake
47
+ requirement: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ type: :development
53
+ prerelease: false
54
+ version_requirements: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ - !ruby/object:Gem::Dependency
60
+ name: rspec
61
+ requirement: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: 3.3.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 3.3.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: rubocop
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ - !ruby/object:Gem::Dependency
88
+ name: sqlite3
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 1.3.10
94
+ type: :development
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: 1.3.10
101
+ description:
102
+ email: huacnlee@gmail.com
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - README.md
108
+ - lib/generators/settings/settings_generator.rb
109
+ - lib/generators/settings/templates/migration.rb
110
+ - lib/generators/settings/templates/model.rb
111
+ - lib/ruby-settings-cached.rb
112
+ - lib/ruby-settings/cached_settings.rb
113
+ - lib/ruby-settings/configuration.rb
114
+ - lib/ruby-settings/extend.rb
115
+ - lib/ruby-settings/scoped_settings.rb
116
+ - lib/ruby-settings/settings.rb
117
+ homepage: https://github.com/RobotJiang/ruby-settings-cached
118
+ licenses: []
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '2.0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.4.5
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: This is improved from rails-settings, added caching. Settings is a plugin
140
+ that makes managing a table of global key, value pairs easy. Think of it like a
141
+ global Hash stored in you database, that uses simple ActiveRecord like methods for
142
+ manipulation. Keep track of any global setting that you dont want to hard code
143
+ into your rails app. You can store any kind of object. Strings, numbers, arrays,
144
+ or any object. Ported to Rails 3!
145
+ test_files: []