settingson 1.4.1 → 1.5.12

Sign up to get free protection for your applications and to get access to all the features.
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)