run_time_settings 0.1.0
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 +7 -0
- data/README.md +120 -0
- data/Rakefile +15 -0
- data/lib/run_time_settings.rb +11 -0
- data/lib/run_time_settings/persistent_attributes.rb +67 -0
- data/lib/run_time_settings/settings.rb +39 -0
- data/lib/run_time_settings/type/time.rb +23 -0
- data/lib/run_time_settings/version.rb +5 -0
- metadata +176 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0547302343cffb55114807f167926c1dda688718f572b985e56605c9020ae155
|
4
|
+
data.tar.gz: d0abf2cb43695acb5f42fca3d82e1417a7943ec163f3b27430f536f4ab48af31
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8f3d032ed5789b10d4616e0029bba210e940b1066ad8752395ec911e669a94d1c7cc84bb5b00c1d00016412e4cd9c06f05af498cd1f66182c0c739de91b52c37
|
7
|
+
data.tar.gz: dfae24669973f55748e23e69c89203fc722d98084a0479a86ed7833d018397d03b1776680770ada5149e1efae2a9898c4434e1d6c5cf5d0cc7e04eae5ab6b5b2
|
data/README.md
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+

|
2
|
+

|
3
|
+
[](https://codeclimate.com/github/RockSolt/run_time_settings/maintainability)
|
4
|
+
|
5
|
+
# RunTimeSettings
|
6
|
+
|
7
|
+
Run time is the most important part. If you're okay with doing a deployment to update a setting, then that sounds like an environment variable (for which there are lots of good solutions). However, if you find yourself wanting to change a value more frequently, or you want someone without the ability to do a deployment to be able to change a value, then run-time settings might be for you.
|
8
|
+
|
9
|
+
In the end these are just namespaced key-value pairs stored in the database. You could create a settings model (and we do!) with a key attribute and a value attribute and you'd have just about the same thing. But it's ruby and it's rails, so you want a few more features from your settings:
|
10
|
+
|
11
|
+
- type castings so that 'true' returns true and '42' return 42
|
12
|
+
- default values
|
13
|
+
- predicate methods for boolean settings
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Settings can be declared on any class—a PORO or an ActiveRecord can declare settings.
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class BatchJob
|
21
|
+
setting :last_run, :date
|
22
|
+
setting :enabled, :boolean, default: false
|
23
|
+
setting :percentage, :float
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
The settings are then available via accessors on the class:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
BatchJob.last_run = Date.today
|
31
|
+
BatchJob.enabled?
|
32
|
+
BatchJob.percentage
|
33
|
+
```
|
34
|
+
|
35
|
+
### Types
|
36
|
+
|
37
|
+
The following types are available to use:
|
38
|
+
- big_integer
|
39
|
+
- boolean
|
40
|
+
- date
|
41
|
+
- datetime
|
42
|
+
- decimal
|
43
|
+
- float
|
44
|
+
- integer
|
45
|
+
- string
|
46
|
+
- time
|
47
|
+
|
48
|
+
Note: The <tt>time</tt> type does not store milliseconds.
|
49
|
+
|
50
|
+
## Installation
|
51
|
+
|
52
|
+
Add this line to your application's Gemfile:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
gem 'run_time_settings'
|
56
|
+
```
|
57
|
+
|
58
|
+
And then execute:
|
59
|
+
|
60
|
+
$ bundle install
|
61
|
+
|
62
|
+
Or install it yourself as:
|
63
|
+
|
64
|
+
$ gem install run_time_settings
|
65
|
+
|
66
|
+
### Migration for `run_time_settings` Table
|
67
|
+
|
68
|
+
The table must be created before settings can be used. Run the following command to generate a migration for the `run_time_settings` table:
|
69
|
+
|
70
|
+
rails g migration CreateRunTimeSettings namespace:string key_name:string db_value:string
|
71
|
+
|
72
|
+
It should generate a migration that looks something like this:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class CreateRunTimeSettings < ActiveRecord::Migration[6.0]
|
76
|
+
def change
|
77
|
+
create_table :run_time_settings do |t|
|
78
|
+
t.string :namespace
|
79
|
+
t.string :key_name
|
80
|
+
t.string :db_value
|
81
|
+
t.timestamps
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
|
88
|
+
## Development
|
89
|
+
|
90
|
+
Guard runs both [RuboCop](https://docs.rubocop.org/en/stable/) and [RSpec](https://relishapp.com/rspec). Rubocop is
|
91
|
+
configured to auto-correct safe issues.
|
92
|
+
|
93
|
+
Start [Guard](https://github.com/guard/guard) at the command line: `bundle exec guard`
|
94
|
+
|
95
|
+
Both can be run manually from the command line:
|
96
|
+
|
97
|
+
`rubocop`
|
98
|
+
|
99
|
+
`bundle exec rspec`
|
100
|
+
|
101
|
+
Run the console with the following:
|
102
|
+
|
103
|
+
`bundle exec rake console`
|
104
|
+
|
105
|
+
### Database
|
106
|
+
|
107
|
+
The tests (and the console) use an in-memory database, so there is no prior setup required. It gets created each time.
|
108
|
+
|
109
|
+
## Contributing
|
110
|
+
|
111
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/RockSolt/run_time_settings. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/RockSolt/run_time_settings/blob/master/CODE_OF_CONDUCT.md).
|
112
|
+
|
113
|
+
|
114
|
+
## License
|
115
|
+
|
116
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
117
|
+
|
118
|
+
## Code of Conduct
|
119
|
+
|
120
|
+
Everyone interacting in the RunTimeSettings project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/RockSolt/run_time_settings/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
task :console do
|
9
|
+
require 'irb'
|
10
|
+
require 'irb/completion'
|
11
|
+
require 'run_time_settings'
|
12
|
+
require_relative 'spec/database'
|
13
|
+
ARGV.clear
|
14
|
+
IRB.start
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'run_time_settings/version'
|
4
|
+
|
5
|
+
require 'run_time_settings/persistent_attributes'
|
6
|
+
require 'run_time_settings/settings'
|
7
|
+
|
8
|
+
module RunTimeSettings
|
9
|
+
class Error < StandardError; end
|
10
|
+
# Your code goes here...
|
11
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'run_time_settings/type/time'
|
5
|
+
|
6
|
+
module RunTimeSettings
|
7
|
+
# = Persistent Attributes
|
8
|
+
module PersistentAttributes
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
# Specifies a class-level, persistent attribute. The class (not the
|
13
|
+
# instance) receives getter and setter methods for the setting.
|
14
|
+
# Additionally, boolean settings add predicate methods.
|
15
|
+
#
|
16
|
+
# +setting_name+ The name of the setting.
|
17
|
+
#
|
18
|
+
# +type+ A symbol such as +:string+ or +:integer+, or a type object to be
|
19
|
+
# used for this attribute. See ActiveModel::Type for list of symbols /
|
20
|
+
# delivered types.
|
21
|
+
#
|
22
|
+
# === Options
|
23
|
+
# The following options are accepted:
|
24
|
+
#
|
25
|
+
# +default+ The default value to use when no value is provided.
|
26
|
+
#
|
27
|
+
# When using a symbol for +cast_type+, extra options are forwarded to the
|
28
|
+
# constructor of the type object.
|
29
|
+
#
|
30
|
+
# === Examples
|
31
|
+
#
|
32
|
+
# A BatchJob class declares <tt>setting :last_run, :date</tt>, which will
|
33
|
+
# add the following:
|
34
|
+
# * <tt>BatchJob.last_run</tt>
|
35
|
+
# * <tt>BatchJob.last_run=(date)</tt>
|
36
|
+
#
|
37
|
+
# A BatchJob class declares <tt>setting :enabled, :boolean, default: false</tt>,
|
38
|
+
# which will add the following:
|
39
|
+
# * <tt>BatchJob.enabled</tt>
|
40
|
+
# * <tt>BatchJob.enabled=(boolean)</tt>
|
41
|
+
# * <tt>BatchJob.enabled?</tt>
|
42
|
+
def setting(setting_name, type = ActiveModel::Type::Value.new, **options)
|
43
|
+
setting_name = setting_name.to_s
|
44
|
+
type = RunTimeSettings::Type::Time.new if type == :time
|
45
|
+
type = ActiveModel::Type.lookup(type, **options.except(:default)) if type.is_a?(Symbol)
|
46
|
+
|
47
|
+
RunTimeSettings::Settings.add_setting_type(name, setting_name, type)
|
48
|
+
define_setting_accessors(setting_name, options[:default], type.is_a?(ActiveModel::Type::Boolean))
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def define_setting_accessors(setting_name, default, boolean)
|
54
|
+
define_singleton_method(setting_name) do
|
55
|
+
value = RunTimeSettings::Settings.read(name, setting_name)
|
56
|
+
value.nil? ? default : value
|
57
|
+
end
|
58
|
+
|
59
|
+
define_singleton_method("#{setting_name}?") { public_send(setting_name) } if boolean
|
60
|
+
|
61
|
+
define_singleton_method("#{setting_name}=") do |value|
|
62
|
+
RunTimeSettings::Settings.write(name, setting_name, value)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module RunTimeSettings
|
6
|
+
# Settings
|
7
|
+
#
|
8
|
+
# Model settings holds namespaced key-value pairs. This acts as the data store for the PersistentAttributes mixin.
|
9
|
+
# See RunTimeSettings::PersistentAttributes.settings for information.
|
10
|
+
class Settings < ActiveRecord::Base
|
11
|
+
self.table_name = :run_time_settings
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def add_setting_type(namespace, key, type)
|
15
|
+
setting_types[[namespace, key]] = type
|
16
|
+
end
|
17
|
+
|
18
|
+
def read(namespace, key)
|
19
|
+
value = RunTimeSettings::Settings.find_by(namespace: namespace, key_name: key)&.db_value
|
20
|
+
type_for(namespace, key).deserialize(value) if value.present?
|
21
|
+
end
|
22
|
+
|
23
|
+
def write(namespace, key, value)
|
24
|
+
setting = RunTimeSettings::Settings.find_or_initialize_by(namespace: namespace, key_name: key)
|
25
|
+
setting.update!(db_value: type_for(namespace, key).serialize(value))
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def type_for(namespace, key)
|
31
|
+
setting_types[[namespace, key]]
|
32
|
+
end
|
33
|
+
|
34
|
+
def setting_types
|
35
|
+
@setting_types ||= {}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RunTimeSettings
|
4
|
+
module Type
|
5
|
+
# = Time
|
6
|
+
#
|
7
|
+
# Custom type caster for Time. Values are converted to an integer representing seconds since epoch for storage in
|
8
|
+
# the database, then converted back to Time on the way out.
|
9
|
+
#
|
10
|
+
# This is only accurate to the second; milliseconds are lost.
|
11
|
+
class Time
|
12
|
+
# called by read, should return Time instance
|
13
|
+
def deserialize(value)
|
14
|
+
::Time.at(value.to_i)
|
15
|
+
end
|
16
|
+
|
17
|
+
# called by write, should convert to unix epoch for storage in database
|
18
|
+
def serialize(value)
|
19
|
+
value.to_i
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: run_time_settings
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Todd Kummer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-10-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: guard
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.16'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.16'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: guard-rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.7'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: guard-rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.9'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.9'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.90.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.90.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.19'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.19'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: sqlite3
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.4.2
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 1.4.2
|
139
|
+
description: Easily add and manage application-level settings
|
140
|
+
email:
|
141
|
+
- todd@rockridgesolutions.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- README.md
|
147
|
+
- Rakefile
|
148
|
+
- lib/run_time_settings.rb
|
149
|
+
- lib/run_time_settings/persistent_attributes.rb
|
150
|
+
- lib/run_time_settings/settings.rb
|
151
|
+
- lib/run_time_settings/type/time.rb
|
152
|
+
- lib/run_time_settings/version.rb
|
153
|
+
homepage: https://github.com/RockSolt/run_time_settings
|
154
|
+
licenses:
|
155
|
+
- MIT
|
156
|
+
metadata: {}
|
157
|
+
post_install_message:
|
158
|
+
rdoc_options: []
|
159
|
+
require_paths:
|
160
|
+
- lib
|
161
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 2.3.0
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
171
|
+
requirements: []
|
172
|
+
rubygems_version: 3.1.2
|
173
|
+
signing_key:
|
174
|
+
specification_version: 4
|
175
|
+
summary: Persistent, run-time application settings
|
176
|
+
test_files: []
|