settingson 1.4.1 → 1.5.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d855dba93399013f3232112fb5c387ec630a2d2
4
- data.tar.gz: 7f82756e384c88d1da5c9e94447f675196edd1ae
3
+ metadata.gz: 46d441faeb98c67815ddeb8588cc3b6c7ee19a17
4
+ data.tar.gz: 31eae27b20ceca3b9a8fea750f9f50774f45c953
5
5
  SHA512:
6
- metadata.gz: cd0c3532cd6169d0e581b9e7bcf9d7d71802f6e4ee63d2dc4704fa13f4665c84f64625eea004b1e87959ff9c39c60655dae49f63a7b1dc2912be7ce209e866d1
7
- data.tar.gz: 547abb27ae4c7000997ec3d682a6f3e280aaf8f2151500d850ecea675c4b78cad0faaa7e2871b1985666a8ff106a4caaf75caf7495de31bb603c0617be61e75b
6
+ metadata.gz: 7d9857097bf89d3a7b3c5a747299078a42b858638aa967feabdfeda7477713c03b287e0739e57b252b873370723f0285f97b2457eb08f718e39d5d9641c1ad2d
7
+ data.tar.gz: 611c40af49e3c325fd6bf7d227a54975d97441440298626d1a7da8eef19ebc09882782372aaeae92c79943fbaf667cc2423f579a7b926f527c8e7ae79c34dc0b
data/.gitignore CHANGED
@@ -11,15 +11,19 @@ doc/
11
11
  lib/bundler/man
12
12
  pkg
13
13
  rdoc
14
- spec/reports
14
+ /tmp
15
15
  test/tmp
16
16
  test/version_tmp
17
- tmp
18
17
  *.bundle
19
18
  *.so
20
19
  *.o
21
20
  *.a
22
21
  mkmf.log
22
+ spec/reports
23
23
  spec/dummy/db/development.sqlite3
24
24
  spec/dummy/db/test.sqlite3
25
25
  spec/dummy/log/*
26
+ spec/dummy/tmp/*
27
+ !spec/dummy/tmp/cache
28
+ spec/dummy/tmp/cache/*
29
+ !spec/dummy/tmp/cache/.keep
data/README.md CHANGED
@@ -1,10 +1,44 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/settingson.svg)](http://badge.fury.io/rb/settingson)
2
2
  [![Build Status](https://travis-ci.org/daanforever/settingson.svg?branch=master)](https://travis-ci.org/daanforever/settingson)
3
+ [![Code Climate](https://codeclimate.com/github/daanforever/settingson/badges/gpa.svg)](https://codeclimate.com/github/daanforever/settingson)
3
4
 
4
5
  # Settingson
5
6
 
6
7
  Simple settings management for applications (Ruby on Rails 4 with ActiveRecord)
7
8
 
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'settingson'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```console
20
+ $ bundle
21
+ ```
22
+
23
+ Or install it yourself as:
24
+
25
+ ```console
26
+ $ gem install settingson
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```console
32
+ rails g settingson MODEL
33
+ ```
34
+ Replace MODEL by the class name used for the applications settings, it's frequently `Settings` but it may also be `Configuration` or something else. This will create a model (if one does not exist) and configure it with default options.
35
+
36
+ Next, you'll usually run
37
+ ```console
38
+ rake db:migrate
39
+ ```
40
+ as the generator will have created a migration file (if your ORM supports them).
41
+
8
42
  ## Example
9
43
 
10
44
  shell commands:
@@ -29,8 +63,10 @@ Settings.server.smtp.port # => 25
29
63
 
30
64
  Settings.from_hash({hello: :world})
31
65
  Settings.hello # => :world
66
+ Settings.hello? # => true
32
67
 
33
68
  Settings.not_found # => ""
69
+ Settings.not_found? # => false
34
70
  Settings.not_found.nil? # => true
35
71
  Settings.not_found.empty? # => true
36
72
  Settings.not_found.blank? # => true
@@ -47,34 +83,6 @@ Settings.all # =>
47
83
  # #<Settings id: 5, key: "hello", value: :world, created_at: "2015-12-08 15:18:32", updated_at: "2015-12-08 15:18:32">]
48
84
  ```
49
85
 
50
- ### Cached values
51
-
52
- Caching implemented via ActiveSupport::Cache::Store [(read more)](http://guides.rubyonrails.org/caching_with_rails.html).
53
-
54
- By default 10 seconds:
55
- ```ruby
56
- Settings.hello.world = 'message' # => 'message'
57
- Settings.cached.hello.world # => 'message' with asking DB
58
- Settings.cached.hello.world # => 'message' without asking DB
59
- sleep 11
60
- Settings.cached.hello.world # => 'message' with asking DB
61
- ```
62
-
63
- You can change time to Live:
64
- ```ruby
65
- Settings.cached(30.minutes).hello.world # => 'message'
66
- # same as
67
- Settings.cached(1800).hello.world # => 'message'
68
- ```
69
-
70
- Benchmark results:
71
- ```ruby
72
- puts Benchmark.measure { 1.upto(10000){ Settings.hello.world }}
73
- # => 36.210000 0.680000 36.890000 ( 37.372218)
74
- puts Benchmark.measure { 1.upto(10000){ Settings.cached.hello.world }}
75
- # => 7.140000 0.060000 7.200000 ( 7.246746)
76
- ```
77
-
78
86
  ### Using with [Simple Form](https://github.com/plataformatec/simple_form) and [Haml](https://github.com/haml/haml)
79
87
  in view:
80
88
  ```ruby
@@ -90,9 +98,9 @@ in controller:
90
98
  class SettingsController < ApplicationController
91
99
  def update
92
100
  if Settings.from_hash(params[:settings])
93
- flash[:notice] = t('settings_updated', default: 'Settings updated successfully')
101
+ flash.now[:notice] = t('settings_updated', default: 'Settings updated successfully')
94
102
  else
95
- flash[:alert] = t('settings_not_updated', default: 'Settings not updated')
103
+ flash.now[:alert] = t('settings_not_updated', default: 'Settings not updated')
96
104
  end
97
105
  render :edit
98
106
  end
@@ -122,39 +130,6 @@ Rails.application.config.after_initialize do
122
130
  end
123
131
  ```
124
132
 
125
- ## Installation
126
-
127
- Add this line to your application's Gemfile:
128
-
129
- ```ruby
130
- gem 'settingson'
131
- ```
132
-
133
- And then execute:
134
-
135
- ```console
136
- $ bundle
137
- ```
138
-
139
- Or install it yourself as:
140
-
141
- ```console
142
- $ gem install settingson
143
- ```
144
-
145
- ## Usage
146
-
147
- ```console
148
- rails g settingson MODEL
149
- ```
150
- Replace MODEL by the class name used for the applications settings, it's frequently `Settings` but it may also be `Configuration` or something else. This will create a model (if one does not exist) and configure it with default options.
151
-
152
- Next, you'll usually run
153
- ```console
154
- rake db:migrate
155
- ```
156
- as the generator will have created a migration file (if your ORM supports them).
157
-
158
133
  ## Contributing
159
134
 
160
135
  1. Fork it ( https://github.com/daanforever/settingson/fork )
@@ -2,9 +2,79 @@ module Settingson::Base
2
2
 
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ module ClassMethods
6
+
7
+ # Settings.configure do |config|
8
+ # config.cache.expires = 600 # default: 600
9
+ # config.cache.enabled = true # default: true
10
+ # end
11
+ #
12
+ # # or
13
+ #
14
+ # Settings.configure.expires = 600
15
+ # Settings.configure.enabled = true
16
+
17
+ def configure
18
+ @_settings ||= ::Settingson::Config.new
19
+ yield @_settings if block_given?
20
+ @_settings
21
+ end
22
+
23
+ # Settings.defaults do |settings|
24
+ # settings.server.host = 'host'
25
+ # settings.server.port = 80
26
+ # end
27
+ # FIXME: not ready yet
28
+ def defaults
29
+ Rails.application.config.after_initialize do
30
+ begin
31
+ yield new(settingson: 'defaults') if block_given?
32
+ rescue
33
+ Rails.logger.warn('Settingson::defaults failed')
34
+ end
35
+ end
36
+ true
37
+ end
38
+
39
+ # Settings.from_hash('smtp.host' => 'host')
40
+
41
+ def cached(*args)
42
+ ActiveSupport::Deprecation.warn('Now caching is enabled by default')
43
+ self.new
44
+ end
45
+
46
+ def from_hash(attributes)
47
+ case attributes
48
+ when Hash
49
+ attributes.map{|k,v| find_or_create_by(key: k).update!(value: v)}
50
+ Rails.cache.clear
51
+ true
52
+ else
53
+ raise ArgumentError, 'Hash required', caller
54
+ end
55
+ end
56
+
57
+ def method_missing(symbol, *args)
58
+ super
59
+ rescue NameError
60
+ self.new.send(symbol, *args)
61
+ rescue NoMethodError
62
+ self.new.send(symbol, *args)
63
+ end
64
+
65
+
66
+ end # module ClassMethods
67
+
5
68
  included do
6
69
  attr_accessor :settingson
7
70
  serialize :value
71
+ before_destroy :delete_cached
72
+ end
73
+
74
+ def delete_cached
75
+ cache_key = "#{self.class.configure.cache.namespace}/#{self.key}"
76
+ Rails.cache.delete(cache_key)
77
+ Rails.logger.debug("#{self.class.name}: delete '#{self.key}' '#{cache_key}'")
8
78
  end
9
79
 
10
80
  def to_s
@@ -25,142 +95,57 @@ module Settingson::Base
25
95
 
26
96
  alias empty? nil?
27
97
 
28
- def _settingson_fresh_value
29
- self.class.find_by(key: @settingson)
30
- end
31
-
32
- def _settingson_cached(expires_in)
33
- @_settingson_cached = expires_in
34
- self
35
- end
36
-
37
- def _settingson_cached_value
38
- Rails.cache.fetch("settingson_cache/#{@settingson}", expires_in: @_settingson_cached) do
39
- _settingson_fresh_value
40
- end
41
- end
42
-
43
- def _settingson_value
44
- if @_settingson_cached
45
- _settingson_cached_value
46
- else
47
- _settingson_fresh_value
48
- end
49
- end
50
-
51
- def _settingson_find_or_create(key)
52
- if @settingson.blank?
53
- @settingson = key
54
- else
55
- @settingson += ".#{key}"
56
- end
57
- end
58
-
59
98
  def method_missing(symbol, *args)
60
99
  super
100
+ rescue NameError
101
+ rescue_action(symbol.to_s, args.first)
61
102
  rescue NoMethodError
103
+ rescue_action(symbol.to_s, args.first)
104
+ end # method_missing
62
105
 
63
- case symbol.to_s
64
- when /(.+)=/ # setter
65
-
66
- _settingson_find_or_create($1)
106
+ protected
67
107
 
68
- if args.first.nil? and record = _settingson_fresh_value
69
- record.destroy
70
- elsif record = _settingson_fresh_value
71
- record.update!(value: args.first)
72
- else
73
- self.class.create(key: @settingson, value: args.first)
74
- end
75
-
76
- Rails.cache.delete("settingson_cache/#{@settingson}")
77
-
78
- when /(.+)\?$/ # returns boolean
79
-
80
- _settingson_find_or_create($1)
81
- _settingson_value.present?
82
-
83
- when /(.+)\!$/ # returns self or nil
84
-
85
- _settingson_find_or_create($1)
86
- _settingson_value
108
+ def cached_key
109
+ [ self.class.configure.cache.namespace, @settingson ].join('/')
110
+ end
87
111
 
112
+ def rescue_action(key, value)
113
+ case key
114
+ when /(.+)=/ # setter
115
+ @settingson = [@settingson, $1].compact.join('.')
116
+ record = self.class.find_or_create_by!(key: @settingson)
117
+ record.update!(value: value)
118
+ Rails.cache.write(cached_key, value)
119
+ Rails.logger.debug("#{self.class.name}##{__method__} setter '#{cached_key}'")
120
+ record.value
88
121
  else # returns values or self
89
-
90
- _settingson_find_or_create(symbol.to_s)
91
-
92
- if record = _settingson_value
93
- record.value
94
- else
95
- self
96
- end
97
-
122
+ @settingson = [@settingson, key].compact.join('.')
123
+ Rails.logger.debug("#{self.class.name}##{__method__} getter '#{@settingson}'")
124
+ cached_value_or_self
98
125
  end
99
126
  end
100
127
 
101
- module ClassMethods
102
-
103
- # Settings.defaults do
104
- # Settings.server.host? || Settings.server.host = 'host'
105
- # Settings.server.port? || Settings.server.port = 80
106
- # end
107
-
108
- def defaults(&block)
109
- Rails.application.config.after_initialize do
110
- begin
111
- yield
112
- rescue
113
- Rails.logger.warn('Settingson::defaults failed')
114
- end
115
- end
116
- end
117
-
118
- def from_hash(attributes)
119
- case attributes
120
- when Hash
121
- attributes.map{|k,v| find_or_create_by(key: k).update!(value: v)}
122
- else
123
- false
124
- end
125
- end
126
-
127
- def method_missing(symbol, *args)
128
- super
129
- rescue NoMethodError
130
-
131
- case symbol.to_s
132
- when /(.+)=/ # setter
133
-
134
- @settingson = $1
135
-
136
- if record = find_by(key: @settingson) and args.first.nil?
137
- record.destroy
138
- elsif record
139
- record.update(value: args.first)
140
- else
141
- self.create(key: @settingson,
142
- value: args.first,
143
- settingson: @settingson)
144
- end
145
- when /(.+)\?$/ # returns boolean
146
- find_by(key: $1).present?
147
- when /(.+)\!$/ # returns self or nil
148
- find_by(key: $1)
149
- else # getter
150
-
151
- if record = find_by(key: symbol.to_s)
152
- record.value
153
- else
154
- new(settingson: symbol.to_s)
155
- end
156
-
157
- end
158
- end
128
+ def cached_value_or_self
129
+ result = cached_value
130
+ result.is_a?(ActiveRecord::RecordNotFound) ? self : result
131
+ end
159
132
 
160
- def cached(expires_in = 10.seconds)
161
- new._settingson_cached(expires_in)
133
+ def cached_value
134
+ Rails.logger.debug("#{self.class.name}##{__method__} '#{@settingson}'")
135
+ Rails.cache.fetch(
136
+ cached_key,
137
+ expires_in: self.class.configure.cache.expires,
138
+ race_condition_ttl: self.class.configure.cache.race_condition_ttl
139
+ ) do
140
+ Rails.logger.debug("#{self.class.name}: fresh '#{@settingson}'")
141
+ fresh_value
162
142
  end
143
+ end
163
144
 
164
- end # module ClassMethods
145
+ def fresh_value
146
+ self.class.find_by!(key: @settingson).value
147
+ rescue ActiveRecord::RecordNotFound
148
+ ActiveRecord::RecordNotFound.new
149
+ end
165
150
 
166
- end
151
+ end # Settingson::Base
@@ -0,0 +1,11 @@
1
+ class Settingson::Config
2
+ attr_accessor :cache
3
+
4
+ def initialize
5
+ @cache = OpenStruct.new(expires_in: 60.seconds,
6
+ race_condition_ttl: 10.seconds,
7
+ enabled: true,
8
+ namespace: "settingson/#{Rails.env}"
9
+ )
10
+ end
11
+ end
@@ -1,4 +1,4 @@
1
1
  module Settingson::Store
2
2
 
3
3
 
4
- end
4
+ end
@@ -1,3 +1,3 @@
1
1
  module Settingson
2
- VERSION = "1.4.1"
2
+ VERSION = "1.5.12"
3
3
  end
data/lib/settingson.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "settingson/version"
2
+ require 'settingson/config'
2
3
 
3
4
  module Settingson
4
5
  if defined?(Rails)
@@ -3,49 +3,48 @@ require 'spec_helper'
3
3
  describe Settings do
4
4
 
5
5
  describe 'Settings.defaults' do
6
- # very bad spec. TODO: rewrite me
7
6
  it 'not raises errors' do
8
7
  expect{ Settings.default {} }.to_not raise_error
9
8
  end
10
9
  end
11
10
 
12
- it 'not raises error on create new instance of Settings' do
13
- expect{ Settings.new }.to_not raise_error
14
- end
15
- it 'not raises error on create new element' do
16
- expect{ Settings.hello = Faker::Lorem.word }.to_not raise_error
17
- end
18
- it 'returns same Fixnum' do
19
- word = Faker::Lorem.word
20
- Settings.number = 100
21
- expect( Settings.number ).to eq(100)
22
- end
23
- it 'returns same String' do
24
- word = Faker::Lorem.word
25
- Settings.hello = word
26
- expect( Settings.hello ).to eq(word)
27
- end
28
- it 'returns same value for complex key #1' do
29
- word = Faker::Lorem.word
30
- Settings.hello.hello = word
31
- expect( Settings.hello.hello ).to eq(word)
32
- end
33
- it 'returns same value for complex key #2' do
34
- word = Faker::Lorem.word
35
- Settings.i.hello = word
36
- expect( Settings.i.hello ).to eq(word)
37
- end
38
-
39
- it 'destroys record with nil value #1' do
40
- word = Faker::Lorem.word
41
- Settings.some = word
42
- expect{ Settings.some = nil }.to change{ Settings.count }.by(-1)
43
- end
11
+ describe 'general' do
12
+ it 'not raises error on create new instance of Settings' do
13
+ expect{ Settings.new }.to_not raise_error
14
+ end
15
+ it 'not raises error on create new element' do
16
+ expect{ Settings.hello = Faker::Lorem.word }.to_not raise_error
17
+ end
18
+ it 'returns same Fixnum' do
19
+ word = Faker::Lorem.word
20
+ Settings.number = 100
21
+ expect( Settings.number ).to eq(100)
22
+ end
23
+ it 'returns same String' do
24
+ word = Faker::Lorem.word
25
+ Settings.hello = word
26
+ expect( Settings.hello ).to eq(word)
27
+ end
28
+ it 'returns same value for complex key #1' do
29
+ word = Faker::Lorem.word
30
+ Settings.hello.hello = word
31
+ expect( Settings.hello.hello ).to eq(word)
32
+ end
33
+ it 'returns same value for complex key #2' do
34
+ word = Faker::Lorem.word
35
+ Settings.i.hello = word
36
+ expect( Settings.i.hello ).to eq(word)
37
+ end
38
+ it 'not destroys record with nil value #1' do
39
+ word = Faker::Lorem.word
40
+ Settings.some = word
41
+ expect{ Settings.some = nil }.to change{ Settings.count }.by(0)
42
+ end
44
43
 
45
- it 'destroys record with nil value #2' do
46
- word = Faker::Lorem.word
47
- Settings.some.hello = word
48
- expect{ Settings.some.hello = nil }.to change{ Settings.count }.by(-1)
44
+ it 'not destroys record with nil value #2' do
45
+ Settings.some.hello = Faker::Lorem.word
46
+ expect{ Settings.some.hello = nil }.to change{ Settings.count }.by(0)
47
+ end
49
48
  end
50
49
 
51
50
  describe 'with empty value' do
@@ -70,28 +69,18 @@ describe Settings do
70
69
  end
71
70
  end
72
71
 
73
- describe '::cached' do
74
- it 'not raises error without params' do
75
- expect{ Settings.cached }.to_not raise_error
76
- end
77
-
78
- it 'not raises error with params' do
79
- expect{ Settings.cached(Random.rand(10)) }.to_not raise_error
80
- end
81
-
82
- it 'returns instance of self class' do
83
- expect( Settings.cached ).to be_a(Settings)
72
+ describe 'caching' do
73
+ it 'delete key before destroy' do
74
+ Settings.some.hello = Faker::Lorem.word
75
+ Settings.all.each{|e| e.destroy! }
76
+ expect( Rails.cache.exist?('settingson_cache/some.hello') ).to be false
84
77
  end
85
78
 
86
- it 'returns same value for complex key #1' do
87
- word = Faker::Lorem.word
88
- Settings.hello.hello = word
89
- expect( Settings.cached.hello.hello ).to eq(word)
90
- end
91
- it 'returns same value for complex key #2' do
92
- word = Faker::Lorem.word
93
- Settings.i.hello = word
94
- expect( Settings.cached.i.hello ).to eq(word)
79
+ it 'returns empty value after destroy' do
80
+ Settings.some.hello = Faker::Lorem.word
81
+ Settings.all.each{|e| e.destroy! }
82
+ expect( Settings.some.hello.to_s ).to be_empty
95
83
  end
96
84
  end
85
+
97
86
  end
data/spec/spec_helper.rb CHANGED
@@ -38,6 +38,7 @@ RSpec.configure do |config|
38
38
 
39
39
  config.around(:each) do |example|
40
40
  DatabaseCleaner.cleaning do
41
+ Rails.cache.clear rescue nil
41
42
  example.run
42
43
  end
43
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: settingson
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - dan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-14 00:00:00.000000000 Z
11
+ date: 2016-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -141,6 +141,7 @@ files:
141
141
  - lib/generators/settingson/settingson_generator.rb
142
142
  - lib/generators/settingson/templates/migrations/rename_name_to_key_on_settings.rb
143
143
  - lib/settingson.rb
144
+ - lib/settingson/config.rb
144
145
  - lib/settingson/engine.rb
145
146
  - lib/settingson/store.rb
146
147
  - lib/settingson/version.rb
@@ -214,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
215
  version: '0'
215
216
  requirements: []
216
217
  rubyforge_project:
217
- rubygems_version: 2.4.6
218
+ rubygems_version: 2.4.8
218
219
  signing_key:
219
220
  specification_version: 4
220
221
  summary: Settings management for Ruby on Rails 4 applications (ActiveRecord)