markevans-configurable 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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.markdown +50 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/configurable.gemspec +45 -0
- data/lib/configurable.rb +42 -0
- data/spec/configurable_spec.rb +76 -0
- metadata +62 -0
data/.document
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2009 Mark Evans
|
|
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.markdown
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Configurable
|
|
2
|
+
============
|
|
3
|
+
This is just a simple module which provides an object with a nice API for configuring it.
|
|
4
|
+
|
|
5
|
+
The best explanation is with an example.
|
|
6
|
+
Here we configure the `ImageProcessor` class.
|
|
7
|
+
|
|
8
|
+
First declare which attributes we want to be configurable.
|
|
9
|
+
|
|
10
|
+
class ImageProcessor
|
|
11
|
+
|
|
12
|
+
extend Configurable
|
|
13
|
+
|
|
14
|
+
configurable_attr :processing_lib # defaults to nil
|
|
15
|
+
configurable_attr :default_format, 'png' # defaults to 'png'
|
|
16
|
+
|
|
17
|
+
# ...other stuff...
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Then we can configure them as we need
|
|
22
|
+
|
|
23
|
+
ImageProcessor.configure do |c|
|
|
24
|
+
c.processing_lib = 'imagemagick'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Note that we can NOT configure the ImageProcessor by just saying `ImageProcessor.processing_lib = 'imagemagick'`, the only way is via the `configure` method.
|
|
28
|
+
|
|
29
|
+
We can see what the configuration is at any time like so:
|
|
30
|
+
|
|
31
|
+
ImageProcessor.configuration # {:processing_lib => 'imagemagick', :default_format => 'png'}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
Why not just use attr_accessors?
|
|
35
|
+
------------------------------
|
|
36
|
+
It's more of a conceptual win really. By limiting the configuration of these attributes to the `configure` method, the user knows that they are dealing with the configuration of the object.
|
|
37
|
+
Also we are able to view the configuration with `ImageProcessor.configuration` because we've kept them separate from other accessor methods.
|
|
38
|
+
|
|
39
|
+
Why not just use a `ImageProcessor.config` hash?
|
|
40
|
+
----------------------------------------------
|
|
41
|
+
Because after configuring an object, the rest of the code shouldn't care whether an attribute had to be configured or not (whereas it would using `ImageProcessor.config[:processing_lib]`).
|
|
42
|
+
This way we can decide later that an attribute should actually be configurable, and this is transparent to the rest of the code.
|
|
43
|
+
|
|
44
|
+
Install
|
|
45
|
+
--------
|
|
46
|
+
Usual way for github gems.
|
|
47
|
+
|
|
48
|
+
Copyright
|
|
49
|
+
--------
|
|
50
|
+
Copyright (c) 2009 Mark Evans. See LICENSE for details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'jeweler'
|
|
6
|
+
Jeweler::Tasks.new do |gem|
|
|
7
|
+
gem.name = "configurable"
|
|
8
|
+
gem.summary = "Simple module for making your class configurable"
|
|
9
|
+
gem.email = "mark@new-bamboo.co.uk"
|
|
10
|
+
gem.homepage = "http://github.com/markevans/configurable"
|
|
11
|
+
gem.authors = ["Mark Evans"]
|
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
rescue LoadError
|
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
require 'spec/rake/spectask'
|
|
20
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
|
21
|
+
spec.libs << 'lib' << 'spec'
|
|
22
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
|
26
|
+
spec.libs << 'lib' << 'spec'
|
|
27
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
|
28
|
+
spec.rcov = true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
task :default => :spec
|
|
33
|
+
|
|
34
|
+
require 'rake/rdoctask'
|
|
35
|
+
Rake::RDocTask.new do |rdoc|
|
|
36
|
+
if File.exist?('VERSION.yml')
|
|
37
|
+
config = YAML.load(File.read('VERSION.yml'))
|
|
38
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
|
39
|
+
else
|
|
40
|
+
version = ""
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
44
|
+
rdoc.title = "Configurable #{version}"
|
|
45
|
+
rdoc.rdoc_files.include('README*')
|
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
47
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{configurable}
|
|
5
|
+
s.version = "0.1.0"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Mark Evans"]
|
|
9
|
+
s.date = %q{2009-07-01}
|
|
10
|
+
s.email = %q{mark@new-bamboo.co.uk}
|
|
11
|
+
s.extra_rdoc_files = [
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.markdown"
|
|
14
|
+
]
|
|
15
|
+
s.files = [
|
|
16
|
+
".document",
|
|
17
|
+
".gitignore",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"README.markdown",
|
|
20
|
+
"Rakefile",
|
|
21
|
+
"VERSION",
|
|
22
|
+
"configurable.gemspec",
|
|
23
|
+
"lib/configurable.rb",
|
|
24
|
+
"spec/configurable_spec.rb"
|
|
25
|
+
]
|
|
26
|
+
s.has_rdoc = true
|
|
27
|
+
s.homepage = %q{http://github.com/markevans/configurable}
|
|
28
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
29
|
+
s.require_paths = ["lib"]
|
|
30
|
+
s.rubygems_version = %q{1.3.1}
|
|
31
|
+
s.summary = %q{Simple module for making your class configurable}
|
|
32
|
+
s.test_files = [
|
|
33
|
+
"spec/configurable_spec.rb"
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
if s.respond_to? :specification_version then
|
|
37
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
38
|
+
s.specification_version = 2
|
|
39
|
+
|
|
40
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
41
|
+
else
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/configurable.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Configurable
|
|
2
|
+
|
|
3
|
+
# Exceptions
|
|
4
|
+
class NothingToConfigure < StandardError; end
|
|
5
|
+
class BadConfigAttribute < StandardError; end
|
|
6
|
+
|
|
7
|
+
def configure(&blk)
|
|
8
|
+
raise NothingToConfigure, "You called configure but there are no configurable attributes" if configuration_hash.empty?
|
|
9
|
+
config_attributes = configuration_hash.keys
|
|
10
|
+
struct_class = Struct.new(*config_attributes)
|
|
11
|
+
struct = struct_class.new(*configuration_hash.values)
|
|
12
|
+
begin
|
|
13
|
+
yield(struct)
|
|
14
|
+
rescue NoMethodError => e
|
|
15
|
+
raise BadConfigAttribute, "You tried to configure using '#{e.name}', but the valid config attributes are #{config_attributes.map{|a| %('#{a}') }.sort.join(', ')}"
|
|
16
|
+
end
|
|
17
|
+
struct.each_pair{|k,v| configuration_hash[k] = v }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def configuration
|
|
21
|
+
configuration_hash.dup
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def configurable_attr attribute, default=nil
|
|
27
|
+
configuration_hash[attribute] = default
|
|
28
|
+
class << self
|
|
29
|
+
self # Get the singleton class of the extended object
|
|
30
|
+
end.class_eval do
|
|
31
|
+
# Define the reader on the extended object
|
|
32
|
+
define_method(attribute) do
|
|
33
|
+
configuration_hash[attribute]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def configuration_hash
|
|
39
|
+
@configuration_hash ||= {}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'spec'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/configurable'
|
|
3
|
+
|
|
4
|
+
describe Configurable do
|
|
5
|
+
|
|
6
|
+
before(:each) do
|
|
7
|
+
class Car
|
|
8
|
+
extend Configurable
|
|
9
|
+
configurable_attr :colour
|
|
10
|
+
configurable_attr :top_speed, 216
|
|
11
|
+
def self.other_thing=(thing); end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "setup" do
|
|
16
|
+
it "should provide attr_readers for configurable attributes" do
|
|
17
|
+
Car.should respond_to(:colour)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should not provide attr_writers for configurable attributes" do
|
|
21
|
+
Car.should_not respond_to(:colour=)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should set default values for configurable attributes" do
|
|
25
|
+
Car.top_speed.should == 216
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should set the default as nil if not specified" do
|
|
29
|
+
Car.colour.should be_nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should allow specifying configurable attrs as strings" do
|
|
33
|
+
class Bike
|
|
34
|
+
extend Configurable
|
|
35
|
+
configurable_attr 'colour', 'rude'
|
|
36
|
+
end
|
|
37
|
+
Bike.colour.should == 'rude'
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
describe "configuring" do
|
|
43
|
+
it "should raise an error if there are no configurable attributes" do
|
|
44
|
+
class None; extend Configurable; end
|
|
45
|
+
lambda {
|
|
46
|
+
None.configure{|c|}
|
|
47
|
+
}.should raise_error(Configurable::NothingToConfigure)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should allow you to change values" do
|
|
51
|
+
Car.configure do |c|
|
|
52
|
+
c.colour = 'red'
|
|
53
|
+
end
|
|
54
|
+
Car.colour.should == 'red'
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should not allow you to call other methods on the object via the configuration" do
|
|
58
|
+
lambda{
|
|
59
|
+
Car.configure do |c|
|
|
60
|
+
c.other_thing = 5
|
|
61
|
+
end
|
|
62
|
+
}.should raise_error(Configurable::BadConfigAttribute)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "getting configuration" do
|
|
67
|
+
it "should return the configuration as a hash" do
|
|
68
|
+
Car.configuration.should == {:colour => nil, :top_speed => 216}
|
|
69
|
+
end
|
|
70
|
+
it "should not allow you to change the configuration via the hash" do
|
|
71
|
+
Car.configuration[:top_speed] = 555
|
|
72
|
+
Car.top_speed.should == 216
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: markevans-configurable
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Mark Evans
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-07-01 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description:
|
|
17
|
+
email: mark@new-bamboo.co.uk
|
|
18
|
+
executables: []
|
|
19
|
+
|
|
20
|
+
extensions: []
|
|
21
|
+
|
|
22
|
+
extra_rdoc_files:
|
|
23
|
+
- LICENSE
|
|
24
|
+
- README.markdown
|
|
25
|
+
files:
|
|
26
|
+
- .document
|
|
27
|
+
- .gitignore
|
|
28
|
+
- LICENSE
|
|
29
|
+
- README.markdown
|
|
30
|
+
- Rakefile
|
|
31
|
+
- VERSION
|
|
32
|
+
- configurable.gemspec
|
|
33
|
+
- lib/configurable.rb
|
|
34
|
+
- spec/configurable_spec.rb
|
|
35
|
+
has_rdoc: true
|
|
36
|
+
homepage: http://github.com/markevans/configurable
|
|
37
|
+
post_install_message:
|
|
38
|
+
rdoc_options:
|
|
39
|
+
- --charset=UTF-8
|
|
40
|
+
require_paths:
|
|
41
|
+
- lib
|
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: "0"
|
|
47
|
+
version:
|
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: "0"
|
|
53
|
+
version:
|
|
54
|
+
requirements: []
|
|
55
|
+
|
|
56
|
+
rubyforge_project:
|
|
57
|
+
rubygems_version: 1.2.0
|
|
58
|
+
signing_key:
|
|
59
|
+
specification_version: 2
|
|
60
|
+
summary: Simple module for making your class configurable
|
|
61
|
+
test_files:
|
|
62
|
+
- spec/configurable_spec.rb
|