config_accessor 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+ gemspec
3
+
4
+ group :development do
5
+ gem 'rspec'
6
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Alexey Mikhaylov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,34 @@
1
+ == Synopsys
2
+ Class-level configuration DSL
3
+
4
+ == Installation
5
+ gem install config_accessor
6
+
7
+ == Examples
8
+ require 'config_accessor'
9
+
10
+ class Remote
11
+ configurable!
12
+
13
+ config_accessor :host, :default => "localhost"
14
+ config_accessor :port, :default => "80", :transform => :to_i
15
+ config_accessor :proxy_host, :proxy_port
16
+ end
17
+
18
+ class Local < Remote
19
+ config_accessor :l_port
20
+ end
21
+
22
+ Remote.host # => "localhost"
23
+ Remote.port # => 80
24
+ Remote.proxy_host # => nil
25
+
26
+ r = Remote.new
27
+
28
+ r.port = "81"
29
+ r.port # => 81
30
+ Remote.port # => 80
31
+ Remote.port = 82
32
+ r.port # => 81
33
+
34
+ Local.port # => 80
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "config_accessor/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "config_accessor"
7
+ s.version = ConfigAccessor::VERSION
8
+ s.authors = ["Alexei Mikhailov"]
9
+ s.email = ["amikhailov83@gmail.com"]
10
+ s.homepage = "https://github.com/take-five/config_accessor"
11
+ s.summary = %q{Class-level configurations}
12
+
13
+ s.rubyforge_project = "config_accessor"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ # specify any dependencies here; for example:
21
+ s.add_development_dependency "rspec"
22
+ # s.add_runtime_dependency "rest-client"
23
+ end
@@ -0,0 +1,95 @@
1
+ module ConfigAccessor
2
+ module ClassMethods
3
+ # config_accessor(symbol...) => nil
4
+ #
5
+ # Declare a named config attribute for this class
6
+ # Allowed options:
7
+ # * :transform - Symbol, Proc or Method that must be applied to configuration value before set
8
+ # * :default - Default value for this config section
9
+ # * :alias - alias name for configuration section
10
+ def config_accessor(*names)
11
+ # extract options
12
+ options = names.last.is_a?(Hash) ? names.pop : {}
13
+
14
+ # convert strings to symbols
15
+ names.map!(&:to_sym)
16
+
17
+ raise ArgumentError, 'config accessors names expected' unless names.length > 0
18
+
19
+ raise ArgumentError, ':alias option should be set '\
20
+ 'if and only if one argument supplied' if options.has_key?(:alias) &&
21
+ names.length != 1
22
+
23
+ names.each do |name|
24
+ define_config_accessor(name, options)
25
+ end
26
+
27
+ nil
28
+ end
29
+ alias config_accessors config_accessor
30
+
31
+ # Defines an instance and a singleton method with (optionally) alias.
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
49
+ end
50
+
51
+ private
52
+ # create universal config accessor
53
+ 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
73
+ end
74
+
75
+ # set default value
76
+ accessor.call(options.delete(:default)) if options.has_key?(:default)
77
+
78
+ # add method
79
+ define_config_method(name, accessor, options.delete(:alias))
80
+
81
+ # return nil
82
+ nil
83
+ 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
+ end
95
+ end
@@ -0,0 +1,33 @@
1
+ module ConfigAccessor
2
+ # Both instance and class-level methods
3
+ module InstanceMethods
4
+ def configure(&block)
5
+ raise ArgumentError, 'Block expected' unless block_given?
6
+
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
15
+ end
16
+
17
+ # Reads configuration value (supports inheritance)
18
+ def read_config_value(name)
19
+ parent_config_accessors.merge(@_config_accessors || {})[name.to_sym]
20
+ end
21
+
22
+ protected
23
+ # inheritable config accessors array
24
+ def defined_config_accessors #:nodoc:
25
+ @_config_accessors ||= {}
26
+ end
27
+
28
+ def parent_config_accessors #:nodoc:
29
+ superklass = (self.is_a?(Class) ? self : self.class).superclass
30
+ superklass.respond_to?(:defined_config_accessors) ? superklass.defined_config_accessors : {}
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module ConfigAccessor
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,22 @@
1
+ require "config_accessor/version"
2
+ require "config_accessor/class_methods"
3
+ require "config_accessor/instance_methods"
4
+
5
+ module ConfigAccessor
6
+ def configurable
7
+ extend(ClassMethods)
8
+
9
+ extend(InstanceMethods)
10
+ include(InstanceMethods)
11
+ end
12
+ alias configurable! configurable
13
+
14
+ def try_duplicate(obj) #:nodoc:
15
+ duplicable = [NilClass, TrueClass, FalseClass, Numeric, Symbol, Class, Module].none? { |klass| obj.is_a?(klass) }
16
+
17
+ duplicable ? obj.dup : obj
18
+ end
19
+ module_function :try_duplicate
20
+ end
21
+
22
+ Object.extend(ConfigAccessor)
@@ -0,0 +1,106 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe ConfigAccessor do
4
+ it "should be configurable" do
5
+ c = Class.new {
6
+ configurable!
7
+
8
+ config_accessor :a
9
+ }
10
+ c.should respond_to(:a)
11
+ c.new.should respond_to(:a)
12
+
13
+ c.new.should_not respond_to(:config_accessor)
14
+ end
15
+
16
+ it "should be configurable in subclasses" do
17
+ c = Class.new {
18
+ configurable!
19
+
20
+ config_accessor :a
21
+ }
22
+ d = Class.new(c) {}
23
+
24
+ d.should respond_to(:a)
25
+ d.new.should respond_to(:a)
26
+ end
27
+
28
+ it "should be able to set configuration values" do
29
+ c = Class.new {
30
+ configurable!
31
+
32
+ config_accessor :port
33
+ port 80
34
+ }
35
+ d = Class.new(c) {}
36
+ instance = c.new
37
+
38
+ c.port.should eq(80)
39
+ instance.port.should eq(80)
40
+ d.port.should eq(80)
41
+
42
+ instance.port 81
43
+ d.port.should eq(80)
44
+ end
45
+
46
+ it "should not mutate class configuration through instance" do
47
+ c = Class.new {
48
+ configurable!
49
+
50
+ config_accessor :port, :ary
51
+ port 80
52
+ ary []
53
+ }
54
+ instance = c.new
55
+
56
+ instance.port 81
57
+ instance.ary << 1
58
+
59
+ instance.port.should eq(81)
60
+ instance.ary.should eq([1])
61
+
62
+ c.port.should eq(80)
63
+ c.ary.should eq([])
64
+
65
+ c.port 82
66
+ instance.port.should eq(81)
67
+ end
68
+
69
+ it "should be able to set default values" do
70
+ c = Class.new {
71
+ configurable!
72
+
73
+ config_accessor :port, :default => 80
74
+ }
75
+ c.port.should eq(80)
76
+ end
77
+
78
+ it "should be able to define aliases" do
79
+ c = Class.new {
80
+ configurable!
81
+
82
+ config_accessor :port, :alias => :inferred_port, :default => 80
83
+ }
84
+ c.inferred_port.should eq(80)
85
+ end
86
+
87
+ it "should accept blocks as values" do
88
+ c = Class.new {
89
+ configurable!
90
+
91
+ config_accessor :transformer
92
+ transformer { 22 }
93
+ }
94
+ c.transformer.should be_a_kind_of(Proc)
95
+ end
96
+
97
+ it "should transform values" do
98
+ c = Class.new {
99
+ configurable!
100
+
101
+ config_accessor :port, :transform => :to_i
102
+ }
103
+ c.port "80"
104
+ c.port.should eq(80)
105
+ end
106
+ end
@@ -0,0 +1,5 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup
4
+
5
+ require "config_accessor"
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: config_accessor
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Alexei Mikhailov
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-12-10 00:00:00 +06:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ description:
34
+ email:
35
+ - amikhailov83@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - LICENSE
46
+ - README.rdoc
47
+ - Rakefile
48
+ - config_accessor.gemspec
49
+ - lib/config_accessor.rb
50
+ - lib/config_accessor/class_methods.rb
51
+ - lib/config_accessor/instance_methods.rb
52
+ - lib/config_accessor/version.rb
53
+ - spec/config_accessor_spec.rb
54
+ - spec/test_helper.rb
55
+ has_rdoc: true
56
+ homepage: https://github.com/take-five/config_accessor
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project: config_accessor
83
+ rubygems_version: 1.3.7
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Class-level configurations
87
+ test_files: []
88
+