blindgaenger-configurable 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +203 -0
- data/Rakefile +13 -0
- data/examples/brecht.rb +40 -0
- data/examples/computers.config +16 -0
- data/examples/computers.rb +46 -0
- data/examples/triangle.rb +32 -0
- data/examples/website.rb +22 -0
- data/lib/configurable.rb +70 -0
- metadata +68 -0
data/README.textile
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
h1. Configurable
|
2
|
+
|
3
|
+
Little helper to configure ruby instances in a DSLish way.
|
4
|
+
|
5
|
+
|
6
|
+
h2. Usage
|
7
|
+
|
8
|
+
See the @examples/triangle.rb@ for the example described here.
|
9
|
+
|
10
|
+
Include it in your class and define some configuration attributes:
|
11
|
+
|
12
|
+
<pre><code>
|
13
|
+
require 'rubygems'
|
14
|
+
require 'configurable'
|
15
|
+
|
16
|
+
class Triangle
|
17
|
+
include Configurable
|
18
|
+
|
19
|
+
config_accessor :shape
|
20
|
+
config_accessor :color
|
21
|
+
end
|
22
|
+
</code></pre>
|
23
|
+
|
24
|
+
Configure some instances. Each config needs a @key@ to be accessible beside all
|
25
|
+
the other configs. Let's name it after some important mathematics.
|
26
|
+
|
27
|
+
<pre><code>
|
28
|
+
Triangle.configure 'euklid' do
|
29
|
+
shape 'isosceles'
|
30
|
+
color 'red'
|
31
|
+
end
|
32
|
+
|
33
|
+
Triangle.configure 'pythagoras' do
|
34
|
+
shape 'equilateral'
|
35
|
+
color 'blue'
|
36
|
+
end
|
37
|
+
</code></pre>
|
38
|
+
|
39
|
+
Use the configured instances.
|
40
|
+
|
41
|
+
<pre><code>
|
42
|
+
Triangle.configs #=> {"euclid"=>#<Triangle:0x...>, "pythagoras"=>#<Triangle:0x...>}
|
43
|
+
|
44
|
+
Triangle.each {|name, triangle|
|
45
|
+
puts "#{name} => #{triangle.inspect}"
|
46
|
+
}
|
47
|
+
|
48
|
+
Triangle['pythagoras'].shape #=> equilateral
|
49
|
+
</code></pre>
|
50
|
+
|
51
|
+
Of course, feel free to have a look at the "source code":http://github.com/blindgaenger/configurable on Github. ;)
|
52
|
+
|
53
|
+
|
54
|
+
h3. Initalize with the configured key
|
55
|
+
|
56
|
+
In some cases the key you use in the @configure@ method should be available in
|
57
|
+
the model as well. Of course, you could specify it again, but that's not necessary.
|
58
|
+
|
59
|
+
Just define (or maybe you already have) a contructor which is able to receive
|
60
|
+
the specified key. It's up to you, what you do with it.
|
61
|
+
|
62
|
+
<pre><code>
|
63
|
+
class Website
|
64
|
+
include Configurable
|
65
|
+
|
66
|
+
config_accessor :name
|
67
|
+
config_accessor :url
|
68
|
+
|
69
|
+
def initialize(key)
|
70
|
+
@name = key
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Website.configure 'StackOverflow' do
|
75
|
+
url 'http://stackoverflow.com/'
|
76
|
+
end
|
77
|
+
|
78
|
+
so = Website['StackOverflow']
|
79
|
+
so.name #=> StackOverflow
|
80
|
+
so.url #=> http://stackoverflow.com/
|
81
|
+
</code></pre>
|
82
|
+
|
83
|
+
|
84
|
+
h3. Reader, writer or accessor
|
85
|
+
|
86
|
+
The basic @attr_*@ methods are available as @config_*@. They create the getter
|
87
|
+
and setter methods as usual. So you can still define which attributes should be
|
88
|
+
accessible from the outside world.
|
89
|
+
|
90
|
+
<pre><code>
|
91
|
+
class Person
|
92
|
+
include Configurable
|
93
|
+
|
94
|
+
config_reader :birthday # can't change it
|
95
|
+
config_writer :nickname # don't even know how they call you
|
96
|
+
config_accessor :friends # may come and go
|
97
|
+
end
|
98
|
+
|
99
|
+
Person.configure 'Bertolt Brecht' do
|
100
|
+
birthday '1898-02-10'
|
101
|
+
nickname 'Bert'
|
102
|
+
friends 'Hanns Eisler', 'Karl Valentin'
|
103
|
+
end
|
104
|
+
|
105
|
+
brecht = Person['Bertolt Brecht']
|
106
|
+
|
107
|
+
# reader
|
108
|
+
brecht.birthday #=> 1898-02-10
|
109
|
+
begin
|
110
|
+
brecht.birthday = '2008-12-24'
|
111
|
+
rescue NoMethodError => ex
|
112
|
+
end
|
113
|
+
|
114
|
+
# writer
|
115
|
+
brecht.nickname = 'Herr K.'
|
116
|
+
begin
|
117
|
+
brecht.nickname
|
118
|
+
rescue NoMethodError => ex
|
119
|
+
end
|
120
|
+
|
121
|
+
# accessor
|
122
|
+
brecht.friends #=> ["Hanns Eisler", "Karl Valentin"]
|
123
|
+
brecht.friends << 'Carola Neher'
|
124
|
+
brecht.friends #=> ["Hanns Eisler", "Karl Valentin", "Carola Neher"]
|
125
|
+
</code></pre>
|
126
|
+
|
127
|
+
You see, all behave the exact same way!
|
128
|
+
|
129
|
+
|
130
|
+
h3. Use in configuration files
|
131
|
+
|
132
|
+
Please see @examples/computers.rb@ for the working example.
|
133
|
+
|
134
|
+
Ok, at first define the model. Please note, that @type@ is the second parameter
|
135
|
+
of the constructor.
|
136
|
+
|
137
|
+
<pre><code>
|
138
|
+
class Computer
|
139
|
+
include Configurable
|
140
|
+
|
141
|
+
config_accessor :host
|
142
|
+
config_accessor :type
|
143
|
+
config_accessor :ip
|
144
|
+
|
145
|
+
def initialize(host, type)
|
146
|
+
@host = host
|
147
|
+
@type = type
|
148
|
+
end
|
149
|
+
end
|
150
|
+
</code></pre>
|
151
|
+
|
152
|
+
Now define some DSLish config helpers. Each injects a different @type@ as
|
153
|
+
arguments to the @configure@ methods. Use as much arguments as you like. But it's
|
154
|
+
important, that the @key@ (in this case the @name@) is still the first argument.
|
155
|
+
|
156
|
+
<pre><code>
|
157
|
+
def server(name, &block)
|
158
|
+
Computer.configure(name, :server, &block)
|
159
|
+
end
|
160
|
+
|
161
|
+
def notebook(name, &block)
|
162
|
+
Computer.configure(name, :notebook, &block)
|
163
|
+
end
|
164
|
+
</code></pre>
|
165
|
+
|
166
|
+
Create a config file and use the DSL. Although the helpers simply wrap the
|
167
|
+
@configure@ method it looks much nicer!
|
168
|
+
|
169
|
+
<pre><code>
|
170
|
+
server 'raumstation' do
|
171
|
+
ip '192.168.0.201'
|
172
|
+
end
|
173
|
+
|
174
|
+
server 'wohnserver' do
|
175
|
+
ip '192.168.0.202'
|
176
|
+
end
|
177
|
+
|
178
|
+
notebook 'gartenstuhl' do
|
179
|
+
ip '192.168.0.203'
|
180
|
+
end
|
181
|
+
</code></pre>
|
182
|
+
|
183
|
+
Back in your ruby file, load the config and use it as usual.
|
184
|
+
|
185
|
+
<pre><code>
|
186
|
+
config_file = 'computers.config'
|
187
|
+
load config_file
|
188
|
+
|
189
|
+
ips = Computer.map {|name, computer| computer.ip }
|
190
|
+
#=> ["192.168.0.201", "192.168.0.200", "192.168.0.202", "192.168.0.203"]
|
191
|
+
|
192
|
+
raumstation = Computer['raumstation']
|
193
|
+
raumstation.type #=> :server
|
194
|
+
</code></pre>
|
195
|
+
|
196
|
+
That's it!
|
197
|
+
|
198
|
+
|
199
|
+
h2. Contact
|
200
|
+
|
201
|
+
You can contact me via mail at blindgaenger at gmail dot com, or leave me a
|
202
|
+
message on my "Github profile":http://github.com/blindgaenger.
|
203
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec/rake/spectask'
|
2
|
+
|
3
|
+
desc "Run Specs with Rspec"
|
4
|
+
Spec::Rake::SpecTask.new :spec do |t|
|
5
|
+
t.spec_opts = %w(--format specdoc --color)
|
6
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
7
|
+
end
|
8
|
+
|
9
|
+
$:.unshift(File.dirname(__FILE__) + '/../../lib')
|
10
|
+
require 'cucumber/rake/task'
|
11
|
+
Cucumber::Rake::Task.new do |t|
|
12
|
+
t.cucumber_opts = "--format pretty --no-source"
|
13
|
+
end
|
data/examples/brecht.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
$:.unshift File.join(File::dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'configurable'
|
3
|
+
|
4
|
+
class Person
|
5
|
+
include Configurable
|
6
|
+
|
7
|
+
config_reader :birthday # can't change it
|
8
|
+
config_writer :nickname # don't even know how they call you
|
9
|
+
config_accessor :friends # may come and go
|
10
|
+
end
|
11
|
+
|
12
|
+
Person.configure 'Bertolt Brecht' do
|
13
|
+
birthday '1898-02-10'
|
14
|
+
nickname 'Bert'
|
15
|
+
friends 'Hanns Eisler', 'Karl Valentin'
|
16
|
+
end
|
17
|
+
|
18
|
+
brecht = Person['Bertolt Brecht']
|
19
|
+
|
20
|
+
# reader
|
21
|
+
brecht.birthday #=> 1898-02-10
|
22
|
+
begin
|
23
|
+
brecht.birthday = '2008-12-24'
|
24
|
+
rescue NoMethodError => ex
|
25
|
+
#=> undefined method `birthday=' for #<Person:0xb7c30d04>
|
26
|
+
end
|
27
|
+
|
28
|
+
# writer
|
29
|
+
brecht.nickname = 'Herr K.'
|
30
|
+
begin
|
31
|
+
brecht.nickname
|
32
|
+
rescue NoMethodError => ex
|
33
|
+
#=> super: no superclass method `nickname'
|
34
|
+
end
|
35
|
+
|
36
|
+
# accessor
|
37
|
+
brecht.friends #=> ["Hanns Eisler", "Karl Valentin"]
|
38
|
+
brecht.friends << 'Carola Neher'
|
39
|
+
brecht.friends #=> ["Hanns Eisler", "Karl Valentin", "Carola Neher"]
|
40
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
$:.unshift File.join(File::dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'configurable'
|
3
|
+
|
4
|
+
class Computer
|
5
|
+
include Configurable
|
6
|
+
|
7
|
+
attr_accessor :type
|
8
|
+
config_accessor :hostname
|
9
|
+
config_accessor :ip
|
10
|
+
|
11
|
+
def initialize(host, type)
|
12
|
+
@hostname = host
|
13
|
+
@type = type
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# define some DSLish config helpers
|
19
|
+
|
20
|
+
def server(name, &block)
|
21
|
+
Computer.configure(name, :server, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def desktop(name, &block)
|
25
|
+
Computer.configure(name, :desktop, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def notebook(name, &block)
|
29
|
+
Computer.configure(name, :notebook, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# load the config (here from 'computers.config')
|
34
|
+
config_file = $0.gsub /#{File.extname($0)}$/, '.config'
|
35
|
+
load config_file
|
36
|
+
|
37
|
+
|
38
|
+
# now use them
|
39
|
+
|
40
|
+
ips = Computer.map {|name, computer| computer.ip }
|
41
|
+
#=> ["192.168.0.201", "192.168.0.200", "192.168.0.202", "192.168.0.203"]
|
42
|
+
|
43
|
+
Computer['raumstation'] #=> <Computer:0xb7c6e4c4 @type=:server, @hostname="raumstation", @ip="192.168.0.201">
|
44
|
+
Computer['apfelsaft'] #=> <Computer:0xb7c6e62c @type=:desktop, @hostname="apfelsaft", @ip="192.168.0.200">
|
45
|
+
Computer['wohnserver'] #=> <Computer:0xb7c6e370 @type=:server, @hostname="wohnserver", @ip="192.168.0.202">
|
46
|
+
Computer['gartenstuhl'] #=> <Computer:0xb7c6e21c @type=:notebook, @hostname="gartenstuhl", @ip="192.168.0.203">
|
@@ -0,0 +1,32 @@
|
|
1
|
+
$:.unshift File.join(File::dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'configurable'
|
3
|
+
|
4
|
+
class Triangle
|
5
|
+
include Configurable
|
6
|
+
|
7
|
+
config_accessor :shape
|
8
|
+
|
9
|
+
config_accessor :sides do |*args|
|
10
|
+
args.join('->')
|
11
|
+
end
|
12
|
+
|
13
|
+
config_accessor :angles do |alpha, beta, gamma, *others|
|
14
|
+
raise 'more than 3 angles defined' unless others.empty?
|
15
|
+
raise 'sum of all angels is not 180' if alpha + beta + gamma != 180
|
16
|
+
[alpha, beta, gamma]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Triangle.configure('euclid') do
|
21
|
+
shape 'isosceles'
|
22
|
+
sides 'a', 'b', 'c'
|
23
|
+
angles 90, 60, 30
|
24
|
+
end
|
25
|
+
|
26
|
+
p Triangle.configs
|
27
|
+
#=> {"euclid"=>#<Triangle:0xb7d01e90 @sides="a->b->c", @shape="isosceles", @angles=[90, 60, 30]>}
|
28
|
+
|
29
|
+
triangle = Triangle['euclid']
|
30
|
+
p triangle.sides
|
31
|
+
#=> "a->b->c"
|
32
|
+
|
data/examples/website.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$:.unshift File.join(File::dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'configurable'
|
3
|
+
|
4
|
+
class Website
|
5
|
+
include Configurable
|
6
|
+
|
7
|
+
config_accessor :name
|
8
|
+
config_accessor :url
|
9
|
+
|
10
|
+
def initialize(key)
|
11
|
+
@name = key
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Website.configure 'StackOverflow' do
|
16
|
+
url 'http://stackoverflow.com/'
|
17
|
+
end
|
18
|
+
|
19
|
+
so = Website['StackOverflow']
|
20
|
+
so.name #=> StackOverflow
|
21
|
+
so.url #=> http://stackoverflow.com/
|
22
|
+
|
data/lib/configurable.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
module Configurable
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
|
5
|
+
class << base
|
6
|
+
attr_reader :configs
|
7
|
+
include Enumerable
|
8
|
+
def method_missing(name, *args, &block)
|
9
|
+
@configs ||= {}
|
10
|
+
@configs.send(name, *args, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
# based on http://eigenclass.org/hiki.rb?ruby+plugins
|
16
|
+
def base.config_attr(reader, writer, *names, &block)
|
17
|
+
class_eval do
|
18
|
+
names.each do |name|
|
19
|
+
|
20
|
+
define_method(name) do |*args|
|
21
|
+
if args.empty?
|
22
|
+
if reader
|
23
|
+
instance_variable_get("@#{name}")
|
24
|
+
else
|
25
|
+
super # should raise the error
|
26
|
+
end
|
27
|
+
else
|
28
|
+
value = *args
|
29
|
+
value = block.call(*args) if block_given?
|
30
|
+
instance_variable_set("@#{name}", value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if writer
|
35
|
+
attr_writer name.to_sym
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def base.config_accessor(*names, &block)
|
43
|
+
config_attr(true, true, *names, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def base.config_writer(*names, &block)
|
47
|
+
config_attr(false, true, *names, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def base.config_reader(*names, &block)
|
51
|
+
config_attr(true, false, *names, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def base.configure(key, *args, &block)
|
56
|
+
# arity isn't reliable, so just try it
|
57
|
+
begin
|
58
|
+
instance = self.new(key, *args)
|
59
|
+
rescue ArgumentError
|
60
|
+
instance = self.new(*args)
|
61
|
+
end
|
62
|
+
instance.instance_eval &block
|
63
|
+
self[key] = instance
|
64
|
+
instance
|
65
|
+
end
|
66
|
+
|
67
|
+
end # self.included
|
68
|
+
|
69
|
+
end
|
70
|
+
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: blindgaenger-configurable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- blindgaenger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-18 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: cucumber
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.1.15
|
23
|
+
version:
|
24
|
+
description:
|
25
|
+
email: blindgaenger@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- Rakefile
|
34
|
+
- README.textile
|
35
|
+
- lib/configurable.rb
|
36
|
+
- examples/brecht.rb
|
37
|
+
- examples/computers.config
|
38
|
+
- examples/computers.rb
|
39
|
+
- examples/triangle.rb
|
40
|
+
- examples/website.rb
|
41
|
+
has_rdoc: "false"
|
42
|
+
homepage: http://github.com/blindgaenger/configurable
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.2.0
|
64
|
+
signing_key:
|
65
|
+
specification_version: 2
|
66
|
+
summary: Little helper to configure ruby instances in a DSLish way.
|
67
|
+
test_files: []
|
68
|
+
|