config_accessor 0.0.2 → 0.0.3
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.
- data/README.rdoc +17 -1
- data/config_accessor.gemspec +1 -0
- data/lib/config_accessor.rb +1 -0
- data/lib/config_accessor/class_methods.rb +25 -50
- data/lib/config_accessor/config.rb +66 -0
- data/lib/config_accessor/instance_methods.rb +27 -18
- data/lib/config_accessor/version.rb +1 -1
- data/spec/config_accessor_spec.rb +27 -0
- metadata +54 -3
data/README.rdoc
CHANGED
@@ -29,6 +29,22 @@ Class-level configuration DSL
|
|
29
29
|
r.port # => 81
|
30
30
|
Remote.port # => 80
|
31
31
|
Remote.port = 82
|
32
|
+
|
33
|
+
# next expressions are equivalent
|
32
34
|
r.port # => 81
|
35
|
+
r.config[:port] # => 81
|
36
|
+
r.config["port"] # => 81
|
37
|
+
r.config.port # => 81
|
38
|
+
|
39
|
+
# It supports inheritance, subclasses cannot change superclasses configurations
|
40
|
+
Local.port # => 80
|
41
|
+
|
42
|
+
# You can do it with +configure+ method
|
43
|
+
Local.configure do
|
44
|
+
port 81
|
45
|
+
end
|
33
46
|
|
34
|
-
|
47
|
+
# or
|
48
|
+
Local.configure do |config|
|
49
|
+
config.port 81
|
50
|
+
end
|
data/config_accessor.gemspec
CHANGED
@@ -9,6 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = ["amikhailov83@gmail.com"]
|
10
10
|
s.homepage = "https://github.com/take-five/config_accessor"
|
11
11
|
s.summary = %q{Class-level configurations}
|
12
|
+
s.description = File.read(File.expand_path('../README.rdoc', __FILE__))
|
12
13
|
|
13
14
|
s.rubyforge_project = "config_accessor"
|
14
15
|
|
data/lib/config_accessor.rb
CHANGED
@@ -17,7 +17,7 @@ module ConfigAccessor
|
|
17
17
|
raise ArgumentError, 'config accessors names expected' unless names.length > 0
|
18
18
|
|
19
19
|
raise ArgumentError, ':alias option should be set '\
|
20
|
-
|
20
|
+
'if and only if one argument supplied' if options.has_key?(:alias) &&
|
21
21
|
names.length != 1
|
22
22
|
|
23
23
|
names.each do |name|
|
@@ -30,66 +30,41 @@ module ConfigAccessor
|
|
30
30
|
|
31
31
|
# Defines an instance and a singleton method with (optionally) alias.
|
32
32
|
# The method parameter can be a <tt>Proc</tt>, a <tt>Method</tt> or an <tt>UnboundMethod</tt> object.
|
33
|
-
def define_config_method(symbol,
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
33
|
+
def define_config_method(symbol, ali=nil)
|
34
|
+
class_eval <<-CODE
|
35
|
+
class << self # class << self
|
36
|
+
def #{symbol}(*args, &block) # def port(*args, &block)
|
37
|
+
config.#{symbol}(*args, &block) # config.port(*args, &block)
|
38
|
+
end # end
|
39
|
+
alias #{symbol}= #{symbol} # alias port= port
|
40
|
+
#{"alias #{ali} #{symbol}" if ali} # alias inferred_port port
|
41
|
+
#{"alias #{ali}= #{symbol}" if ali} # alias inferred_port= port
|
42
|
+
end # end
|
43
|
+
|
44
|
+
def #{symbol}(*args, &block) # def port(*args, &block)
|
45
|
+
config.#{symbol}(*args, &block) # config.port(*args, &block)
|
46
|
+
end # end
|
47
|
+
alias #{symbol}= #{symbol} # alias port= port
|
48
|
+
#{"alias #{ali} #{symbol}" if ali} # alias inferred_port port
|
49
|
+
#{"alias #{ali}= #{symbol}" if ali} # alias inferred_port= port
|
50
|
+
CODE
|
49
51
|
end
|
50
52
|
|
51
53
|
private
|
52
54
|
# create universal config accessor
|
53
55
|
def define_config_accessor(name, options) #:nodoc:
|
54
|
-
|
55
|
-
|
56
|
-
t.to_proc
|
57
|
-
end
|
58
|
-
|
59
|
-
# create accessor
|
60
|
-
accessor = proc do |*args, &block|
|
61
|
-
if args.empty? && !block # reader
|
62
|
-
read_config_value(name)
|
63
|
-
else # writer
|
64
|
-
raise ArgumentError, 'Too many arguments (%s for 1)' % args.length if args.length > 1
|
65
|
-
|
66
|
-
val = args.first || block
|
67
|
-
# apply :transform
|
68
|
-
val = transform.call(val) if transform.is_a?(Proc)
|
69
|
-
|
70
|
-
# set
|
71
|
-
write_config_value(name, val)
|
72
|
-
end
|
56
|
+
if t = options.delete(:transform)
|
57
|
+
config.register_transformer(name, t)
|
73
58
|
end
|
74
59
|
|
75
|
-
# set default value
|
76
|
-
accessor.call(options.delete(:default)) if options.has_key?(:default)
|
77
|
-
|
78
60
|
# add method
|
79
|
-
define_config_method(name,
|
61
|
+
define_config_method(name, options.delete(:alias))
|
62
|
+
|
63
|
+
# set default value
|
64
|
+
send(name, options.delete(:default)) if options.has_key?(:default)
|
80
65
|
|
81
66
|
# return nil
|
82
67
|
nil
|
83
68
|
end
|
84
|
-
|
85
|
-
# create alias for both singleton and instance methods
|
86
|
-
def define_config_accessor_aliases(accessor_name, alias_name) #:nodoc:
|
87
|
-
class_eval <<-CODE
|
88
|
-
class << self
|
89
|
-
alias #{alias_name} #{accessor_name}
|
90
|
-
end
|
91
|
-
alias #{alias_name} #{accessor_name}
|
92
|
-
CODE
|
93
|
-
end
|
94
69
|
end
|
95
70
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module ConfigAccessor
|
2
|
+
class Config < Hash #:nodoc:
|
3
|
+
attr_reader :transformers
|
4
|
+
|
5
|
+
def initialize(parent)
|
6
|
+
super()
|
7
|
+
|
8
|
+
@transformers = parent.respond_to?(:transformers) ? parent.transformers.dup : {}
|
9
|
+
|
10
|
+
parent.each_pair do |k, v|
|
11
|
+
self[k] = try_duplicate(v)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Make a deep copy of Config
|
16
|
+
def dup
|
17
|
+
Config.new(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def register_transformer(name, proc)
|
21
|
+
raise TypeError, 'transformer must be Symbol, Method or Proc' unless proc.respond_to?(:to_proc)
|
22
|
+
|
23
|
+
@transformers[name.to_sym] = proc.to_proc
|
24
|
+
end
|
25
|
+
|
26
|
+
# indifferent access
|
27
|
+
def [](key)
|
28
|
+
super(key.to_sym)
|
29
|
+
end
|
30
|
+
|
31
|
+
# indifferent access
|
32
|
+
def fetch(key)
|
33
|
+
super(key.to_sym)
|
34
|
+
end
|
35
|
+
|
36
|
+
# indifferent access
|
37
|
+
def []=(key, value)
|
38
|
+
super(key.to_sym, value)
|
39
|
+
end
|
40
|
+
|
41
|
+
# uniform access
|
42
|
+
# c = Config.new
|
43
|
+
# c.port 80
|
44
|
+
# c.port # => 80
|
45
|
+
def access(key, *args, &block)
|
46
|
+
if args.empty? && !block
|
47
|
+
self[key]
|
48
|
+
else
|
49
|
+
raise ArgumentError, 'Too many arguments (%s for 1)' % args.length if args.length > 1
|
50
|
+
|
51
|
+
val = args.first || block
|
52
|
+
val = @transformers[key.to_sym].call(val) if @transformers[key.to_sym].respond_to?(:call)
|
53
|
+
|
54
|
+
self[key] = val
|
55
|
+
end
|
56
|
+
end
|
57
|
+
alias method_missing access
|
58
|
+
|
59
|
+
private
|
60
|
+
def try_duplicate(obj) #:nodoc:
|
61
|
+
duplicable = [NilClass, TrueClass, FalseClass, Numeric, Symbol, Class, Module].none? { |klass| obj.is_a?(klass) }
|
62
|
+
|
63
|
+
duplicable ? obj.dup : obj
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,33 +1,42 @@
|
|
1
1
|
module ConfigAccessor
|
2
2
|
# Both instance and class-level methods
|
3
3
|
module InstanceMethods
|
4
|
+
# Sexy notation:
|
5
|
+
# class Tank
|
6
|
+
# config_accessor :target
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# Tank.configure {
|
10
|
+
# target "localhost:80"
|
11
|
+
# }
|
12
|
+
#
|
13
|
+
# or (result is the same):
|
14
|
+
# Tank.configure do |conf|
|
15
|
+
# conf.target "localhost:80"
|
16
|
+
# end
|
4
17
|
def configure(&block)
|
5
18
|
raise ArgumentError, 'Block expected' unless block_given?
|
6
19
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# Writes names configuration value
|
13
|
-
def write_config_value(name, value)
|
14
|
-
(@_config_accessors ||= {})[name.to_sym] = value
|
20
|
+
if block.arity == 1
|
21
|
+
yield(config)
|
22
|
+
else
|
23
|
+
config.instance_eval(&block)
|
24
|
+
end
|
15
25
|
end
|
16
26
|
|
17
|
-
#
|
18
|
-
def
|
19
|
-
|
27
|
+
# Direct access to configuration values
|
28
|
+
def config
|
29
|
+
if self.is_a?(Class)
|
30
|
+
@_config ||= ConfigAccessor::Config.new(parent_config)
|
31
|
+
else
|
32
|
+
@_config ||= self.class.config.dup
|
33
|
+
end
|
20
34
|
end
|
21
35
|
|
22
36
|
protected
|
23
|
-
|
24
|
-
def defined_config_accessors #:nodoc:
|
25
|
-
@_config_accessors ||= {}
|
26
|
-
end
|
27
|
-
|
28
|
-
def parent_config_accessors #:nodoc:
|
37
|
+
def parent_config #:nodoc:
|
29
38
|
superklass = (self.is_a?(Class) ? self : self.class).superclass
|
30
|
-
superklass.respond_to?(:
|
39
|
+
superklass.respond_to?(:config) ? superklass.config : {}
|
31
40
|
end
|
32
41
|
end
|
33
42
|
end
|
@@ -103,4 +103,31 @@ describe ConfigAccessor do
|
|
103
103
|
c.port "80"
|
104
104
|
c.port.should eq(80)
|
105
105
|
end
|
106
|
+
|
107
|
+
it "should be configurable through configure method" do
|
108
|
+
c = Class.new {
|
109
|
+
configurable!
|
110
|
+
config_accessor :port
|
111
|
+
}
|
112
|
+
|
113
|
+
c.configure {
|
114
|
+
port 80
|
115
|
+
}
|
116
|
+
c.port.should eq(80)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should be compatable with ActiveSupport::Configurable" do
|
120
|
+
c = Class.new {
|
121
|
+
configurable!
|
122
|
+
config_accessor :port
|
123
|
+
}
|
124
|
+
|
125
|
+
i = c.new
|
126
|
+
i.port = 80
|
127
|
+
|
128
|
+
i.config[:port].should eq(80)
|
129
|
+
|
130
|
+
i.configure { |conf| conf[:port] = 81 }
|
131
|
+
i.port.should eq(81)
|
132
|
+
end
|
106
133
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Alexei Mikhailov
|
@@ -30,7 +30,57 @@ dependencies:
|
|
30
30
|
version: "0"
|
31
31
|
type: :development
|
32
32
|
version_requirements: *id001
|
33
|
-
description:
|
33
|
+
description: |-
|
34
|
+
== Synopsys
|
35
|
+
Class-level configuration DSL
|
36
|
+
|
37
|
+
== Installation
|
38
|
+
gem install config_accessor
|
39
|
+
|
40
|
+
== Examples
|
41
|
+
require 'config_accessor'
|
42
|
+
|
43
|
+
class Remote
|
44
|
+
configurable!
|
45
|
+
|
46
|
+
config_accessor :host, :default => "localhost"
|
47
|
+
config_accessor :port, :default => "80", :transform => :to_i
|
48
|
+
config_accessor :proxy_host, :proxy_port
|
49
|
+
end
|
50
|
+
|
51
|
+
class Local < Remote
|
52
|
+
config_accessor :l_port
|
53
|
+
end
|
54
|
+
|
55
|
+
Remote.host # => "localhost"
|
56
|
+
Remote.port # => 80
|
57
|
+
Remote.proxy_host # => nil
|
58
|
+
|
59
|
+
r = Remote.new
|
60
|
+
|
61
|
+
r.port = "81"
|
62
|
+
r.port # => 81
|
63
|
+
Remote.port # => 80
|
64
|
+
Remote.port = 82
|
65
|
+
|
66
|
+
# next expressions are equivalent
|
67
|
+
r.port # => 81
|
68
|
+
r.config[:port] # => 81
|
69
|
+
r.config["port"] # => 81
|
70
|
+
r.config.port # => 81
|
71
|
+
|
72
|
+
# It supports inheritance, subclasses cannot change superclasses configurations
|
73
|
+
Local.port # => 80
|
74
|
+
|
75
|
+
# You can do it with +configure+ method
|
76
|
+
Local.configure do
|
77
|
+
port 81
|
78
|
+
end
|
79
|
+
|
80
|
+
# or
|
81
|
+
Local.configure do |config|
|
82
|
+
config.port 81
|
83
|
+
end
|
34
84
|
email:
|
35
85
|
- amikhailov83@gmail.com
|
36
86
|
executables: []
|
@@ -48,6 +98,7 @@ files:
|
|
48
98
|
- config_accessor.gemspec
|
49
99
|
- lib/config_accessor.rb
|
50
100
|
- lib/config_accessor/class_methods.rb
|
101
|
+
- lib/config_accessor/config.rb
|
51
102
|
- lib/config_accessor/instance_methods.rb
|
52
103
|
- lib/config_accessor/version.rb
|
53
104
|
- spec/config_accessor_spec.rb
|