blindgaenger-configurable 0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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,16 @@
1
+
2
+ desktop 'apfelsaft' do
3
+ ip '192.168.0.200'
4
+ end
5
+
6
+ server 'raumstation' do
7
+ ip '192.168.0.201'
8
+ end
9
+
10
+ server 'wohnserver' do
11
+ ip '192.168.0.202'
12
+ end
13
+
14
+ notebook 'gartenstuhl' do
15
+ ip '192.168.0.203'
16
+ end
@@ -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
+
@@ -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
+
@@ -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
+