configuru 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/.gitignore +25 -0
- data/.travis.yml +15 -0
- data/CHANGELOG.md +0 -0
- data/CONTRIBUTORS.md +1 -0
- data/Gemfile +4 -0
- data/LICENSE.md +22 -0
- data/README.md +83 -0
- data/Rakefile +5 -0
- data/configuru.gemspec +30 -0
- data/lib/configuru.rb +3 -0
- data/lib/configuru/config_methods.rb +117 -0
- data/lib/configuru/configurable.rb +45 -0
- data/lib/configuru/version.rb +3 -0
- data/spec/configuru/config_methods_spec.rb +287 -0
- data/spec/configuru/configurable_spec.rb +76 -0
- data/spec/spec_helper.rb +4 -0
- metadata +124 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5db1722e4793d1f8627e6c8c8b796cdac8e83d50
|
4
|
+
data.tar.gz: 9e45658f486a5d39da387eb2479c172b7aee5f4b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6e8073b7a2cbfd96c44f92ed190c796a7a61cfcbc7363ecca705521a517f5bca2c0a7fe6fd0d88258e5316e1f3cc6542f18d5ffb33f76cc5dd6e66e536104474
|
7
|
+
data.tar.gz: ef1b06f4d8c2238f7414538a2b54ddfe70e2c0d857c86f1bd1d388a0ab3a0c755aeef2078a499b247445c42a6402c52c55137679309f84ae380a05f852bbfb13
|
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
.env
|
7
|
+
.rspec
|
8
|
+
Gemfile.lock
|
9
|
+
InstalledFiles
|
10
|
+
_yardoc
|
11
|
+
coverage
|
12
|
+
doc/
|
13
|
+
lib/bundler/man
|
14
|
+
pkg
|
15
|
+
rdoc
|
16
|
+
spec/reports
|
17
|
+
test/tmp
|
18
|
+
test/version_tmp
|
19
|
+
tmp
|
20
|
+
*.bundle
|
21
|
+
*.so
|
22
|
+
*.o
|
23
|
+
*.a
|
24
|
+
mkmf.log
|
25
|
+
**/.DS_Store
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
File without changes
|
data/CONTRIBUTORS.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* Andrey Pronin <moonfly.msk@gmail.com> aka moonfly (https://github.com/moonfly)
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2014 [CONTRIBUTORS.md](https://github.com/moonfly/configuru/master/CONTRIBUTORS.md)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Configuru
|
2
|
+
|
3
|
+
Provides convenient interface for managing configuration parameters for modules, classes and instances.
|
4
|
+
Requires Ruby version >= 2.1.
|
5
|
+
|
6
|
+
[](https://travis-ci.org/moonfly/configuru)
|
7
|
+
[](https://coveralls.io/r/moonfly/configuru?branch=master)
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'configuru'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install configuru
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
The typical usage scenario is provided below:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'configuru'
|
31
|
+
|
32
|
+
class MyClass
|
33
|
+
include Configuru::Configurable
|
34
|
+
provide_configuration
|
35
|
+
|
36
|
+
def_config_param :secret_key, make_string: true, default: (ENV['SECRET_KEY_'] || '???')
|
37
|
+
def_config_param :color, default: :green,
|
38
|
+
convert: ->(val) { raise "Huh?" unless [:red,:green].include?(val); val }
|
39
|
+
def_config_param :percentage, make_float:true, min:0, max:100, default:100
|
40
|
+
|
41
|
+
def initialize(options,&block)
|
42
|
+
configure(options,&block)
|
43
|
+
configuration.lock
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
my_inst = MyClass.new do |config|
|
48
|
+
config.secret_key = "VERY-SECR-ETKY"
|
49
|
+
config.color = :red
|
50
|
+
config.options_source = "/my/path/to/file/with/options.yml"
|
51
|
+
end
|
52
|
+
|
53
|
+
my_inst.configuration.color #=> :red
|
54
|
+
my_inst.configuration.secret_key #=> "VERY-SECR-ETKY"
|
55
|
+
my_inst.configuration.percentage #=> 100
|
56
|
+
```
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
## Versioning
|
61
|
+
|
62
|
+
Semantic versioning (http://semver.org/spec/v2.0.0.html) is used.
|
63
|
+
|
64
|
+
For a version number MAJOR.MINOR.PATCH, unless MAJOR is 0:
|
65
|
+
|
66
|
+
1. MAJOR version is incremented when incompatible API changes are made,
|
67
|
+
2. MINOR version is incremented when functionality is added in a backwards-compatible manner,
|
68
|
+
3. PATCH version is incremented when backwards-compatible bug fixes are made.
|
69
|
+
|
70
|
+
Major version "zero" (0.y.z) is for initial development. Anything may change at any time.
|
71
|
+
The public API should not be considered stable.
|
72
|
+
|
73
|
+
## Dependencies
|
74
|
+
|
75
|
+
Requires Ruby version >= 2.1
|
76
|
+
|
77
|
+
## Contributing
|
78
|
+
|
79
|
+
1. Fork it ( https://github.com/[my-github-username]/configuru/fork )
|
80
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
81
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
82
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
83
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/configuru.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'configuru/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "configuru"
|
8
|
+
spec.version = Configuru::VERSION
|
9
|
+
spec.authors = ['moonfly (Andrey Pronin)']
|
10
|
+
spec.email = ['moonfly.msk@gmail.com']
|
11
|
+
spec.summary = %q{Configuration for your classes}
|
12
|
+
spec.description = %q{Provides convenient interface for managing configuration parameters for modules, classes and instances.}
|
13
|
+
spec.homepage = 'https://github.com/moonfly/configuru'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.rdoc_options = ['--charset=UTF-8']
|
22
|
+
spec.extra_rdoc_files = %w[README.md CONTRIBUTORS.md LICENSE.md]
|
23
|
+
|
24
|
+
spec.required_ruby_version = '>= 2.1.0'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '>= 1.6'
|
27
|
+
spec.add_development_dependency 'rake'
|
28
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
29
|
+
spec.add_development_dependency 'coveralls'
|
30
|
+
end
|
data/lib/configuru.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Configuru
|
4
|
+
module ConfigMethods
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Class methods
|
10
|
+
module ClassMethods
|
11
|
+
def param_names
|
12
|
+
@param_names ||= []
|
13
|
+
end
|
14
|
+
def param(name,options={})
|
15
|
+
param_names << name.to_sym
|
16
|
+
|
17
|
+
inst_var = "@#{name.to_s}"
|
18
|
+
define_method(name) do
|
19
|
+
if !instance_variable_defined?(inst_var) && options.has_key?(:default)
|
20
|
+
instance_variable_set inst_var, options[:default]
|
21
|
+
end
|
22
|
+
instance_variable_get inst_var
|
23
|
+
end
|
24
|
+
|
25
|
+
define_method("#{name.to_s}=") do |value|
|
26
|
+
if options[:lockable] && is_locked
|
27
|
+
raise ArgumentError.new("'#{name.to_s}' cannot be set at this time")
|
28
|
+
end
|
29
|
+
if options[:not_nil] && value.nil?
|
30
|
+
raise ArgumentError.new("'#{name.to_s}' cannot be nil")
|
31
|
+
end
|
32
|
+
if options[:not_empty] && (value.nil? || value.empty?)
|
33
|
+
raise ArgumentError.new("'#{name.to_s}' cannot be empty")
|
34
|
+
end
|
35
|
+
if options.has_key?(:must_be) && !Array(options[:must_be]).include?(value.class)
|
36
|
+
valid_class = false
|
37
|
+
Array(options[:must_be]).each do |cname|
|
38
|
+
valid_class = true if value.is_a?(cname)
|
39
|
+
end
|
40
|
+
raise ArgumentError.new("Wrong class (#{value.class}) for '#{name.to_s}' value") unless valid_class
|
41
|
+
end
|
42
|
+
if options.has_key?(:must_respond_to)
|
43
|
+
Array(options[:must_respond_to]).each do |mname|
|
44
|
+
raise ArgumentError.new("'#{name.to_s}' must respond to '#{mname}'") unless value.respond_to?(mname)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
value = Hash(value) if options[:make_hash]
|
48
|
+
value = Array(value) if options[:make_array]
|
49
|
+
value = String(value) if options[:make_string]
|
50
|
+
value = value.to_i if options[:make_int]
|
51
|
+
value = value.to_f if options[:make_float]
|
52
|
+
value = !!value if options[:make_bool]
|
53
|
+
if options.has_key?(:max) && (value > options[:max])
|
54
|
+
raise ArgumentError.new("'#{name.to_s}' must no be more than #{options[:max]}")
|
55
|
+
end
|
56
|
+
if options.has_key?(:min) && (value < options[:min])
|
57
|
+
raise ArgumentError.new("'#{name.to_s}' must no be less than #{options[:min]}")
|
58
|
+
end
|
59
|
+
if options.has_key?(:in) && !options[:in].include?(value)
|
60
|
+
raise ArgumentError.new("'#{name.to_s}' is out of range")
|
61
|
+
end
|
62
|
+
if options.has_key?(:convert)
|
63
|
+
if options[:convert].is_a? Symbol
|
64
|
+
value = send options[:convert], value
|
65
|
+
else
|
66
|
+
value = options[:convert].call( value )
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
instance_variable_set inst_var, value
|
71
|
+
end
|
72
|
+
name
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Instance methods
|
77
|
+
def lock(flag=true)
|
78
|
+
@locked = flag
|
79
|
+
end
|
80
|
+
def is_locked
|
81
|
+
@locked = false unless instance_variable_defined?(:@locked)
|
82
|
+
@locked
|
83
|
+
end
|
84
|
+
|
85
|
+
def configure(options={})
|
86
|
+
Hash(options).each_pair do |name,value|
|
87
|
+
if name.to_sym == :options_source
|
88
|
+
self.options_source = value
|
89
|
+
else
|
90
|
+
send("#{name.to_s}=",value)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
yield self if block_given?
|
94
|
+
self
|
95
|
+
end
|
96
|
+
def options_source=(value)
|
97
|
+
sub_options = case value
|
98
|
+
when Hash, Array then value
|
99
|
+
when IO, StringIO, Tempfile then
|
100
|
+
YAML.load(value)
|
101
|
+
when String, Pathname
|
102
|
+
output = {}
|
103
|
+
File.open(value,"r") { |f| output = YAML.load(f) }
|
104
|
+
output
|
105
|
+
else
|
106
|
+
raise ArgumentError.new("Wrong argument class for options_source: #{value.class}")
|
107
|
+
end
|
108
|
+
if sub_options.is_a? Array
|
109
|
+
sub_options.each { |elem| self.options_source=elem }
|
110
|
+
else
|
111
|
+
configure(sub_options)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Configuru
|
2
|
+
module Configurable
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
extend Forwardable
|
6
|
+
def_delegator :configuration_class, :param, :def_config_param
|
7
|
+
def configuration_class
|
8
|
+
@configuration_class ||= Class.new do
|
9
|
+
include Configuru::ConfigMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def provide_configuration(limit_to=false)
|
13
|
+
unless [:base,:class,:module].include?(limit_to)
|
14
|
+
# Add methods to instance
|
15
|
+
include MainMethods
|
16
|
+
include InstanceMethods
|
17
|
+
end
|
18
|
+
unless [:instance,:instances].include?(limit_to)
|
19
|
+
# Add methods to base
|
20
|
+
extend MainMethods
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module MainMethods
|
26
|
+
def configuration
|
27
|
+
@configuruation ||= configuration_class.new
|
28
|
+
end
|
29
|
+
def configure(options,&block)
|
30
|
+
configuration.configure(options,&block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module InstanceMethods
|
35
|
+
def configuration_class
|
36
|
+
self.class.configuration_class
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.included(base)
|
41
|
+
base.extend(ClassMethods)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,287 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configuru::ConfigMethods do
|
4
|
+
before(:each) {
|
5
|
+
class TestSubjectClass
|
6
|
+
include Configuru::ConfigMethods
|
7
|
+
end
|
8
|
+
class TestIoSubjectClass
|
9
|
+
include Configuru::ConfigMethods
|
10
|
+
param :test1
|
11
|
+
param :test2
|
12
|
+
end
|
13
|
+
}
|
14
|
+
let(:subject) { TestSubjectClass.new }
|
15
|
+
let(:opts_spec) { Hash("test1" => "something1", :test2 => "something2") }
|
16
|
+
let(:opts_sio) { StringIO.new(opts_spec.to_yaml) }
|
17
|
+
|
18
|
+
it 'includes class methods' do
|
19
|
+
expect(TestSubjectClass.methods).to include :param, :param_names
|
20
|
+
end
|
21
|
+
it 'returns itself from configure (smoke test)' do
|
22
|
+
expect(subject.configure).to eq subject
|
23
|
+
end
|
24
|
+
it 'allows defining parameters' do
|
25
|
+
class << subject
|
26
|
+
param :test
|
27
|
+
end
|
28
|
+
expect(subject).to respond_to :test
|
29
|
+
expect(subject).to respond_to :test=
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'allows settings variables passed as a hash and/or block' do
|
33
|
+
class << subject
|
34
|
+
param :test1
|
35
|
+
param :test2
|
36
|
+
end
|
37
|
+
subject.configure({test1: "something1"}) do |cfg|
|
38
|
+
cfg.test2 = "something2"
|
39
|
+
end
|
40
|
+
expect(subject.test1).to eq "something1"
|
41
|
+
expect(subject.test2).to eq "something2"
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'keeps track of parameters' do
|
45
|
+
expect(TestIoSubjectClass.param_names).to include :test1, :test2
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'allows loading options from Hash' do
|
49
|
+
class << subject
|
50
|
+
param :test1
|
51
|
+
param :test2
|
52
|
+
end
|
53
|
+
subject.options_source = opts_spec
|
54
|
+
expect(subject.test1).to eq "something1"
|
55
|
+
expect(subject.test2).to eq "something2"
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'allows loading options from StringIO' do
|
59
|
+
class << subject
|
60
|
+
param :test1
|
61
|
+
param :test2
|
62
|
+
end
|
63
|
+
subject.options_source = opts_sio
|
64
|
+
expect(subject.test1).to eq "something1"
|
65
|
+
expect(subject.test2).to eq "something2"
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'allows loading options from an array of sources, later sources take precendence' do
|
69
|
+
class << subject
|
70
|
+
param :test1
|
71
|
+
param :test2
|
72
|
+
end
|
73
|
+
opts_spec1 = opts_spec.clone
|
74
|
+
opts_spec1.delete("test1")
|
75
|
+
opts_spec1[:test2] = "something3"
|
76
|
+
|
77
|
+
subject.options_source = [opts_sio, opts_spec1]
|
78
|
+
expect(subject.test1).to eq "something1"
|
79
|
+
expect(subject.test2).to eq "something3"
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'allows loading options from sources several times, later sources take precendence' do
|
83
|
+
class << subject
|
84
|
+
param :test1
|
85
|
+
param :test2
|
86
|
+
end
|
87
|
+
opts_spec1 = opts_spec.clone
|
88
|
+
opts_spec1.delete("test1")
|
89
|
+
opts_spec1[:test2] = "something3"
|
90
|
+
|
91
|
+
subject.options_source = opts_sio
|
92
|
+
subject.options_source = opts_spec1
|
93
|
+
expect(subject.test1).to eq "something1"
|
94
|
+
expect(subject.test2).to eq "something3"
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'does not allow loading options from an arbitrary value' do
|
98
|
+
class << subject
|
99
|
+
param :test1
|
100
|
+
param :test2
|
101
|
+
end
|
102
|
+
[10,"test1=1;test2=2",nil].each do |value|
|
103
|
+
expect{subject.options_source = value}.to raise_error
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'allows loading options from File/IO' do
|
108
|
+
subject1 = nil
|
109
|
+
subject2 = nil
|
110
|
+
subject3 = nil
|
111
|
+
f = Tempfile.new("test_options.yaml")
|
112
|
+
begin
|
113
|
+
f << opts_spec.to_yaml
|
114
|
+
f.open
|
115
|
+
subject1 = TestIoSubjectClass.new.configure( options_source: f )
|
116
|
+
subject2 = TestIoSubjectClass.new.configure( options_source: f.path )
|
117
|
+
File.open( f.path ) do |real_f|
|
118
|
+
subject3 = TestIoSubjectClass.new.configure( options_source: real_f )
|
119
|
+
end
|
120
|
+
ensure
|
121
|
+
f.close
|
122
|
+
f.unlink
|
123
|
+
end
|
124
|
+
[
|
125
|
+
subject1,
|
126
|
+
subject2,
|
127
|
+
subject3
|
128
|
+
].each do |s|
|
129
|
+
expect(s).not_to be_nil
|
130
|
+
expect(s.test1).to eq "something1"
|
131
|
+
expect(s.test2).to eq "something2"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'allows specifying defaults' do
|
136
|
+
class << subject
|
137
|
+
param :test, default: "something3"
|
138
|
+
end
|
139
|
+
expect(subject.test).to eq "something3"
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'allows restriciting value classes' do
|
143
|
+
class << subject
|
144
|
+
param :test, must_be: [Array,Hash]
|
145
|
+
end
|
146
|
+
expect{subject.test=[]}.not_to raise_error
|
147
|
+
expect{subject.test={}}.not_to raise_error
|
148
|
+
expect{subject.test=nil}.to raise_error
|
149
|
+
expect{subject.test=""}.to raise_error
|
150
|
+
end
|
151
|
+
it 'allows restriciting value classes through duck typing' do
|
152
|
+
class << subject
|
153
|
+
param :test, must_respond_to: [:each_pair, :size]
|
154
|
+
end
|
155
|
+
expect{subject.test=[]}.to raise_error
|
156
|
+
expect{subject.test={}}.not_to raise_error # the only one to respond to both :each_pair AND :size
|
157
|
+
expect{subject.test=nil}.to raise_error
|
158
|
+
expect{subject.test=""}.to raise_error
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'allows locking selected variables' do
|
162
|
+
class << subject
|
163
|
+
param :test1, lockable: true
|
164
|
+
param :test2
|
165
|
+
end
|
166
|
+
expect{subject.test1="1"}.not_to raise_error
|
167
|
+
expect{subject.test2="1"}.not_to raise_error
|
168
|
+
expect(subject.test1).to eq "1"
|
169
|
+
expect(subject.test2).to eq "1"
|
170
|
+
|
171
|
+
subject.lock
|
172
|
+
expect(subject.is_locked).to eq true
|
173
|
+
expect{subject.test1="2"}.to raise_error
|
174
|
+
expect{subject.test2="2"}.not_to raise_error
|
175
|
+
expect(subject.test1).to eq "1"
|
176
|
+
expect(subject.test2).to eq "2"
|
177
|
+
|
178
|
+
subject.lock(false)
|
179
|
+
expect(subject.is_locked).to eq false
|
180
|
+
expect{subject.test1="3"}.not_to raise_error
|
181
|
+
expect{subject.test2="3"}.not_to raise_error
|
182
|
+
expect(subject.test1).to eq "3"
|
183
|
+
expect(subject.test2).to eq "3"
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'allows restricting setting nil or empty variables' do
|
187
|
+
class << subject
|
188
|
+
param :test1, not_nil: true
|
189
|
+
param :test2, not_empty: true
|
190
|
+
end
|
191
|
+
expect{subject.test1="1"}.not_to raise_error
|
192
|
+
expect{subject.test2="1"}.not_to raise_error
|
193
|
+
expect(subject.test1).to eq "1"
|
194
|
+
expect(subject.test2).to eq "1"
|
195
|
+
|
196
|
+
expect{subject.test1=nil}.to raise_error
|
197
|
+
expect{subject.test2=nil}.to raise_error
|
198
|
+
expect(subject.test1).to eq "1"
|
199
|
+
expect(subject.test2).to eq "1"
|
200
|
+
|
201
|
+
expect{subject.test1=""}.not_to raise_error
|
202
|
+
expect{subject.test2=""}.to raise_error
|
203
|
+
expect(subject.test1).to eq ""
|
204
|
+
expect(subject.test2).to eq "1"
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'allows converting to pre-defined types' do
|
208
|
+
class << subject
|
209
|
+
param :test_s, make_string: true
|
210
|
+
param :test_a, make_array: true
|
211
|
+
param :test_h, make_hash: true
|
212
|
+
param :test_i, make_int: true
|
213
|
+
param :test_f, make_float: true
|
214
|
+
param :test_b, make_bool: true
|
215
|
+
end
|
216
|
+
expect{subject.test_s=nil}.not_to raise_error
|
217
|
+
expect(subject.test_s).to be_a String
|
218
|
+
expect(subject.test_s).to eq ""
|
219
|
+
|
220
|
+
expect{subject.test_a=nil}.not_to raise_error
|
221
|
+
expect(subject.test_a).to be_a Array
|
222
|
+
expect(subject.test_a).to eq []
|
223
|
+
|
224
|
+
expect{subject.test_h=nil}.not_to raise_error
|
225
|
+
expect(subject.test_h).to be_a Hash
|
226
|
+
expect(subject.test_h).to eq Hash.new
|
227
|
+
|
228
|
+
expect{subject.test_i=nil}.not_to raise_error
|
229
|
+
expect(subject.test_i).to be_a Integer
|
230
|
+
expect(subject.test_i).to eq 0
|
231
|
+
|
232
|
+
expect{subject.test_f=nil}.not_to raise_error
|
233
|
+
expect(subject.test_f).to be_a Float
|
234
|
+
expect(subject.test_f).to eq 0.0
|
235
|
+
|
236
|
+
expect{subject.test_b=nil}.not_to raise_error
|
237
|
+
expect(subject.test_b).to be_a FalseClass
|
238
|
+
expect(subject.test_b).to eq false
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'allows defining min/max boundaries for values' do
|
242
|
+
class << subject
|
243
|
+
param :test1, min: 10
|
244
|
+
param :test2, max: 'c'
|
245
|
+
end
|
246
|
+
|
247
|
+
expect{subject.test1=11}.not_to raise_error
|
248
|
+
expect{subject.test1=10}.not_to raise_error
|
249
|
+
expect{subject.test1=9}.to raise_error
|
250
|
+
|
251
|
+
expect{subject.test2='b'}.not_to raise_error
|
252
|
+
expect{subject.test2='c'}.not_to raise_error
|
253
|
+
expect{subject.test2='d'}.to raise_error
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'allows defining ranges for values' do
|
257
|
+
class << subject
|
258
|
+
param :test1, in: 3..7
|
259
|
+
param :test2, in: ['a','c']
|
260
|
+
end
|
261
|
+
|
262
|
+
expect{subject.test1=3}.not_to raise_error
|
263
|
+
expect{subject.test1=6}.not_to raise_error
|
264
|
+
expect{subject.test1=9}.to raise_error
|
265
|
+
|
266
|
+
expect{subject.test2='a'}.not_to raise_error
|
267
|
+
expect{subject.test2='c'}.not_to raise_error
|
268
|
+
expect{subject.test2='b'}.to raise_error
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'allows specifying a custom conversion method' do
|
272
|
+
class << subject
|
273
|
+
def check_for_x(value)
|
274
|
+
raise "X is not allowed" if value == "x"
|
275
|
+
"ok"
|
276
|
+
end
|
277
|
+
param :test1, convert: :check_for_x
|
278
|
+
param :test2, convert: ->(value) { value+1 }
|
279
|
+
end
|
280
|
+
expect{subject.test1=3}.not_to raise_error
|
281
|
+
expect(subject.test1).to eq "ok"
|
282
|
+
expect{subject.test1="x"}.to raise_error
|
283
|
+
|
284
|
+
expect{subject.test2=7}.not_to raise_error
|
285
|
+
expect(subject.test2).to eq 8
|
286
|
+
end
|
287
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configuru::Configurable do
|
4
|
+
before(:each) do
|
5
|
+
module TestConfigurableModule
|
6
|
+
include Configuru::Configurable
|
7
|
+
provide_configuration
|
8
|
+
def_config_param :test1
|
9
|
+
end
|
10
|
+
module TestConfigurableModuleBase
|
11
|
+
include Configuru::Configurable
|
12
|
+
provide_configuration :base
|
13
|
+
def_config_param :test1
|
14
|
+
end
|
15
|
+
module TestConfigurableModuleInst
|
16
|
+
include Configuru::Configurable
|
17
|
+
provide_configuration :instances
|
18
|
+
def_config_param :test1
|
19
|
+
end
|
20
|
+
|
21
|
+
class TestConfigurableClass
|
22
|
+
include Configuru::Configurable
|
23
|
+
provide_configuration
|
24
|
+
def_config_param :test1
|
25
|
+
end
|
26
|
+
class TestConfigurableClassBase
|
27
|
+
include Configuru::Configurable
|
28
|
+
provide_configuration :base
|
29
|
+
def_config_param :test1
|
30
|
+
end
|
31
|
+
class TestConfigurableClassInst
|
32
|
+
include Configuru::Configurable
|
33
|
+
provide_configuration :instances
|
34
|
+
def_config_param :test1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'works for modules at base-level' do
|
39
|
+
expect{TestConfigurableModuleBase.configure(test1: "1")}.not_to raise_error
|
40
|
+
expect(TestConfigurableModuleBase.configuration.test1).to eq "1"
|
41
|
+
end
|
42
|
+
it 'does not work for modules at instance-level' do
|
43
|
+
expect{TestConfigurableModuleInst.configure(test1: "1")}.to raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'works for classes at base-level' do
|
47
|
+
expect{TestConfigurableClassBase.configure(test1: "1")}.not_to raise_error
|
48
|
+
expect(TestConfigurableClassBase.configuration.test1).to eq "1"
|
49
|
+
end
|
50
|
+
it 'does not work for classes at instance-level' do
|
51
|
+
expect{TestConfigurableClassInst.configure(test1: "1")}.to raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'works for class instances at instance-level' do
|
55
|
+
subject = TestConfigurableClassInst.new
|
56
|
+
expect{subject.configure(test1: "1")}.not_to raise_error
|
57
|
+
expect(subject.configuration.test1).to eq "1"
|
58
|
+
end
|
59
|
+
it 'does not work for class instances at base-level' do
|
60
|
+
subject = TestConfigurableClassBase.new
|
61
|
+
expect{subject.configure(test1: "1")}.to raise_error
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'provides a separate configuration for each instance and class' do
|
65
|
+
subject1 = TestConfigurableClass.new
|
66
|
+
subject2 = TestConfigurableClass.new
|
67
|
+
|
68
|
+
expect{TestConfigurableClass.configure(test1: "0")}.not_to raise_error
|
69
|
+
expect{subject1.configure(test1: "1")}.not_to raise_error
|
70
|
+
expect{subject2.configure(test1: "2")}.not_to raise_error
|
71
|
+
|
72
|
+
expect(TestConfigurableClass.configuration.test1).to eq "0"
|
73
|
+
expect(subject1.configuration.test1).to eq "1"
|
74
|
+
expect(subject2.configuration.test1).to eq "2"
|
75
|
+
end
|
76
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: configuru
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- moonfly (Andrey Pronin)
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coveralls
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Provides convenient interface for managing configuration parameters for
|
70
|
+
modules, classes and instances.
|
71
|
+
email:
|
72
|
+
- moonfly.msk@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files:
|
76
|
+
- README.md
|
77
|
+
- CONTRIBUTORS.md
|
78
|
+
- LICENSE.md
|
79
|
+
files:
|
80
|
+
- ".gitignore"
|
81
|
+
- ".travis.yml"
|
82
|
+
- CHANGELOG.md
|
83
|
+
- CONTRIBUTORS.md
|
84
|
+
- Gemfile
|
85
|
+
- LICENSE.md
|
86
|
+
- README.md
|
87
|
+
- Rakefile
|
88
|
+
- configuru.gemspec
|
89
|
+
- lib/configuru.rb
|
90
|
+
- lib/configuru/config_methods.rb
|
91
|
+
- lib/configuru/configurable.rb
|
92
|
+
- lib/configuru/version.rb
|
93
|
+
- spec/configuru/config_methods_spec.rb
|
94
|
+
- spec/configuru/configurable_spec.rb
|
95
|
+
- spec/spec_helper.rb
|
96
|
+
homepage: https://github.com/moonfly/configuru
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options:
|
102
|
+
- "--charset=UTF-8"
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.1.0
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 2.2.2
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: Configuration for your classes
|
121
|
+
test_files:
|
122
|
+
- spec/configuru/config_methods_spec.rb
|
123
|
+
- spec/configuru/configurable_spec.rb
|
124
|
+
- spec/spec_helper.rb
|