config_newton 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael Bleigh
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.
@@ -0,0 +1,80 @@
1
+ = ConfigNewton
2
+
3
+ A common pattern for Ruby libraries is to have some kind of configuration that can be set at the library level. ConfigNewton is a simple library that provides a user-friendly way to expose that configuration.
4
+
5
+ == Installation
6
+
7
+ gem install config_newton
8
+
9
+ == Usage
10
+
11
+ require 'config_newton'
12
+
13
+ # The library author sets it up like this:
14
+
15
+ module MyLibrary
16
+ include ConfigNewton
17
+
18
+ configurable do
19
+ property :email
20
+ property :special_sauce, :default => true
21
+ end
22
+ end
23
+
24
+ # And the end user can set it like this:
25
+
26
+ MyLibrary.configure do |config|
27
+ config.email = 'dude@somewhere.com'
28
+ config.special_sauce = false
29
+ end
30
+
31
+ # And the library author can use it like this:
32
+
33
+ module MyLibrary
34
+ class Client
35
+ # ... somewhere in the code ...
36
+ MyLibrary.config.email # => 'dude@somewhere.com'
37
+ end
38
+ end
39
+
40
+ == Other Useful Bits
41
+
42
+ There are a few other useful features of ConfigNewton. For instance, you can convert the configuration to a hash at any time, or just access it like one:
43
+
44
+ MyLibrary.config.to_hash # => {:email => 'dude@somewhere.com', :special_sauce => false}
45
+ MyLibrary[:special_sauce] # => false
46
+
47
+ You can also load user settings from a YAML file quite easily. Let's say you're developing a Rails plugin. You can easily load a <tt>config</tt> directory YAML file like this:
48
+
49
+ MyLibrary.config.load_from("#{Rails.root}/config/my_library.yml", Rails.env)
50
+
51
+ The second argument specified is the "root key" for the configuration, allowing you to easily specify environments or other conditions. Using our examples above the user would create a YAML file in <tt>config/my_library.yml</tt> and populate it like this:
52
+
53
+ development:
54
+ email: just@testing.com
55
+ special_sauce: false
56
+
57
+ production
58
+ email: bob@example.com
59
+ special_sauce: true
60
+
61
+ == Roadmap
62
+
63
+ There's still further I'd like to take this library, here are a few thoughts:
64
+
65
+ Hierarchical Configuration :: Create multi-level configurations that retain an intuitive interface both for the library developer and the user.
66
+ Typed Configurations :: Implement a simple casting system to automatically convert values into desired types.
67
+
68
+
69
+ == Note on Patches/Pull Requests
70
+
71
+ * Fork the project.
72
+ * Make your feature addition or bug fix.
73
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
74
+ * Commit, do not mess with rakefile, version, or history.
75
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
76
+ * Send me a pull request. Bonus points for topic branches.
77
+
78
+ == Copyright
79
+
80
+ Copyright (c) 2010 Intridea, Inc. and Michael Bleigh. See LICENSE for details.
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "config_newton"
8
+ gem.summary = %Q{A simple tool to add class-level configuration to libraries.}
9
+ gem.description = %Q{Library authors can now easily add class-level configuration including YAML loading with just a few lines of code.}
10
+ gem.email = "michael@intridea.com"
11
+ gem.homepage = "http://github.com/intridea/config_newton"
12
+ gem.authors = ["Michael Bleigh"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "config_newton #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,133 @@
1
+ module ConfigNewton
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ base.class_eval do
5
+ @configuration = ConfigNewton::Configuration.new
6
+ end
7
+ end
8
+
9
+ module ClassMethods
10
+ # Configure the class either with a hash
11
+ # or by providing a block. See the documentation
12
+ # for Configuration#set.
13
+ def configure(options = {}, &block)
14
+ config.set(options, &block)
15
+ end
16
+
17
+ # A list of configurable properties.
18
+ def configurables
19
+ configuration.properties
20
+ end
21
+
22
+ # The configuration object.
23
+ def configuration
24
+ @configuration
25
+ end
26
+ alias :config :configuration
27
+
28
+ protected
29
+
30
+ # Add either a single configurable property to
31
+ # the class/module or provide a block that will
32
+ # allow you to set multiple at once.
33
+ #
34
+ # <b>Example:</b>
35
+ #
36
+ #
37
+ def configurable(property = nil, options = {}, &block)
38
+ if block_given?
39
+ @configuration.instance_eval(&block)
40
+ else
41
+ @configuration.add(property, options)
42
+ end
43
+ end
44
+ end
45
+
46
+ class Configuration
47
+ def initialize
48
+ @hash = {}
49
+ @properties = []
50
+ @defaults = {}
51
+ end
52
+
53
+ attr_reader :properties
54
+
55
+ # Add a new property that can be set and read
56
+ # on this configuration.
57
+ #
58
+ # <b>Options:</b>
59
+ #
60
+ # <tt>:default</tt> :: Specify a default value.
61
+ def add(name, options = {})
62
+ raise ArgumentError, "Property name cannot be blank." unless name && name != ""
63
+ @properties << name.to_sym
64
+ @defaults[name.to_sym] = options[:default] if options[:default]
65
+ self.class.class_eval <<-RUBY
66
+ def #{name}
67
+ self[:#{name}]
68
+ end
69
+
70
+ def #{name}=(value)
71
+ self[:#{name}] = value
72
+ end
73
+ RUBY
74
+ end
75
+ alias :property :add
76
+
77
+ # Read an individual property on the configuration.
78
+ def [](property)
79
+ @hash[property.to_sym] || @defaults[property.to_sym]
80
+ end
81
+
82
+ # Set an individual property on the configuration.
83
+ def []=(property, value)
84
+ @hash[property.to_sym] = value
85
+ end
86
+
87
+ # Converts the configuration into a symbol-keyed
88
+ # hash.
89
+ def to_hash
90
+ @defaults.merge(@hash)
91
+ end
92
+
93
+ # Set the properties of the configuration
94
+ # either by providing a hash or by providing
95
+ # a block. The block will yield a configuration
96
+ # object that has method setters and getters.
97
+ #
98
+ # Example:
99
+ #
100
+ # MyClass.config.set do |config|
101
+ # config.property = 123
102
+ # end
103
+ def set(properties = {}, &block)
104
+ if block_given?
105
+ yield self
106
+ else
107
+ @hash.merge!(properties.inject({}){|h,(k,v)| h[k.to_sym] = v; h})
108
+ end
109
+ self
110
+ end
111
+
112
+ # Load configuration from a YAML string. Provide
113
+ # a root node if you want something other than
114
+ # the entire yaml document to be utilized. For
115
+ # example, in Rails, you might provide the
116
+ # Rails environment as a root node.
117
+ def load(yaml_string, root_node = nil)
118
+ hash = YAML::load(yaml_string)
119
+ set(root_node ? hash[root_node] : hash)
120
+ end
121
+
122
+ # Load configuration from a YAML file specified
123
+ # by the path given (or a file pointer). Provide
124
+ # a root node if you want something other than
125
+ # the entire yaml document to be utilized. For
126
+ # example, in Rails, you might provide the
127
+ # Rails environment as a root node.
128
+ def load_from(file_or_path, root_node = 'configuration')
129
+ hash = YAML::load_file(file_or_path)
130
+ set(root_node ? hash[root_node] : hash)
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ describe ConfigNewton::Configuration do
4
+ subject { ConfigNewton::Configuration.new }
5
+
6
+ describe '#add' do
7
+ it 'should be able to add properties' do
8
+ subject.add(:abc)
9
+ subject.abc.should be_nil
10
+ end
11
+
12
+ it 'should be able to have a default' do
13
+ subject.add(:abc, :default => 123)
14
+ subject.abc.should == 123
15
+ end
16
+
17
+ it 'should raise an ArgumentError if no name is passed' do
18
+ lambda{subject.add}.should raise_error(ArgumentError)
19
+ end
20
+ end
21
+
22
+ describe '#to_hash' do
23
+ it 'should be able to convert to a hash' do
24
+ subject.add(:foo, :default => 123)
25
+ subject.add(:bar)
26
+ subject.add(:baz, :default => 890)
27
+ subject.bar = 456
28
+ subject.baz = 789
29
+ subject.to_hash.should == {
30
+ :foo => 123,
31
+ :bar => 456,
32
+ :baz => 789
33
+ }
34
+ end
35
+ end
36
+
37
+ it 'should be able to read and write to properties' do
38
+ subject.add(:abc)
39
+ subject.abc = 123
40
+ subject.abc.should == 123
41
+ end
42
+
43
+
44
+ describe '#[]' do
45
+ before do
46
+ subject.add(:abc)
47
+ subject.abc = 123
48
+ end
49
+
50
+ it 'should retrieve set values' do
51
+ subject[:abc].should == 123
52
+ end
53
+
54
+ it 'should convert to symbol' do
55
+ subject['abc'].should == 123
56
+ end
57
+ end
58
+
59
+ describe '#[]=' do
60
+ before do
61
+ subject.add(:abc)
62
+ end
63
+
64
+ it 'should set the value' do
65
+ subject[:abc] = 123
66
+ end
67
+
68
+ it 'should convert to symbol' do
69
+ subject['abc'] = 123
70
+ end
71
+
72
+ after do
73
+ subject[:abc].should == 123
74
+ end
75
+ end
76
+
77
+ describe '#load' do
78
+ let(:yaml) {
79
+ <<-YAML
80
+ development:
81
+ email: bob@example.com
82
+ special_sauce: false
83
+
84
+ production:
85
+ email: frank@example.com
86
+ special_sauce: false
87
+ YAML
88
+ }
89
+
90
+ before do
91
+ subject.add(:email)
92
+ subject.add(:special_sauce, :default => true)
93
+ end
94
+
95
+ it 'should be able to load from YAML' do
96
+ subject.load(yaml, 'development').email.should == 'bob@example.com'
97
+ subject.load(yaml, 'production').email.should == 'frank@example.com'
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ class SampleClass
4
+ include ConfigNewton
5
+ end
6
+
7
+ describe ConfigNewton do
8
+ describe '.configure' do
9
+ before do
10
+ SampleClass.send(:configurable) do
11
+ property :foo, :default => 123
12
+ property :bar
13
+ property :baz, :default => 890
14
+ end
15
+ end
16
+
17
+ it 'should define the configure method on the class' do
18
+ SampleClass.should be_respond_to(:configure)
19
+ end
20
+
21
+ context 'setting values' do
22
+ before do
23
+ SampleClass.config[:foo] = nil
24
+ SampleClass.config[:bar] = nil
25
+ end
26
+
27
+ it 'should accept a hash' do
28
+ SampleClass.configure(:foo => 330, :bar => 555)
29
+ end
30
+
31
+ it 'should accept a block with an argument' do
32
+ SampleClass.configure do |config|
33
+ config.foo = 330
34
+ config.bar = 555
35
+ end
36
+ end
37
+
38
+ after do
39
+ SampleClass.config.to_hash.should == {
40
+ :foo => 330,
41
+ :bar => 555,
42
+ :baz => 890
43
+ }
44
+ end
45
+ end
46
+
47
+ it 'should accept a block with an argument' do
48
+
49
+ end
50
+ end
51
+
52
+ describe '.configurable' do
53
+ it 'should allow for configurables to be created' do
54
+ SampleClass.send(:configurable, :abc)
55
+ SampleClass.config.should be_respond_to(:abc)
56
+ end
57
+
58
+ it 'should allow for block configurable creation' do
59
+ SampleClass.send(:configurable) do
60
+ property :abc, :default => 123
61
+ property :def
62
+ end
63
+
64
+ SampleClass.config.should be_respond_to(:def)
65
+ SampleClass.config.abc.should == 123
66
+ end
67
+
68
+ it 'should be protected' do
69
+ lambda{SampleClass.configurable(:abc)}.should raise_error(NoMethodError)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'rubygems'
5
+ require 'config_newton'
6
+ require 'spec'
7
+ require 'spec/autorun'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: config_newton
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Michael Bleigh
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-23 00:00:00 -05: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
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ description: Library authors can now easily add class-level configuration including YAML loading with just a few lines of code.
35
+ email: michael@intridea.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - LICENSE
42
+ - README.rdoc
43
+ files:
44
+ - .document
45
+ - .gitignore
46
+ - LICENSE
47
+ - README.rdoc
48
+ - Rakefile
49
+ - VERSION
50
+ - lib/config_newton.rb
51
+ - spec/config_newton/configuration_spec.rb
52
+ - spec/config_newton_spec.rb
53
+ - spec/spec.opts
54
+ - spec/spec_helper.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/intridea/config_newton
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options:
61
+ - --charset=UTF-8
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.3.6
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: A simple tool to add class-level configuration to libraries.
85
+ test_files:
86
+ - spec/config_newton/configuration_spec.rb
87
+ - spec/config_newton_spec.rb
88
+ - spec/spec_helper.rb