config_accessor 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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
- Local.port # => 80
47
+ # or
48
+ Local.configure do |config|
49
+ config.port 81
50
+ end
@@ -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
 
@@ -1,4 +1,5 @@
1
1
  require "config_accessor/version"
2
+ require "config_accessor/config"
2
3
  require "config_accessor/class_methods"
3
4
  require "config_accessor/instance_methods"
4
5
 
@@ -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
- 'if and only if one argument supplied' if options.has_key?(:alias) &&
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, method, ali=nil)
34
- define_method(symbol, method)
35
- define_singleton_method(symbol, method)
36
- define_config_accessor_aliases(symbol, ali.to_sym) if ali
37
- end
38
-
39
- # Clone class-level configuration for each instance
40
- def new(*args, &block) #:nodoc:
41
- instance = super(*args, &block)
42
-
43
- # clone class-level variables
44
- defined_config_accessors.each do |name, val|
45
- instance.write_config_value(name, ConfigAccessor.try_duplicate(val))
46
- end
47
-
48
- instance
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
- transform = if t = options.delete(:transform)
55
- raise TypeError, 'transformer must be Symbol, Method or Proc' unless t.respond_to?(:to_proc)
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, accessor, options.delete(:alias))
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
- self.instance_eval(&block)
8
-
9
- self
10
- end
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
- # Reads configuration value (supports inheritance)
18
- def read_config_value(name)
19
- parent_config_accessors.merge(@_config_accessors || {})[name.to_sym]
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
- # inheritable config accessors array
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?(:defined_config_accessors) ? superklass.defined_config_accessors : {}
39
+ superklass.respond_to?(:config) ? superklass.config : {}
31
40
  end
32
41
  end
33
42
  end
@@ -1,3 +1,3 @@
1
1
  module ConfigAccessor
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  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
- - 2
9
- version: 0.0.2
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