jeckyl 0.2.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -4,6 +4,14 @@
4
4
 
5
5
  == History
6
6
 
7
+ [jeckyl-0.2.3 21-Sep-2012]
8
+
9
+ Add references to online docs etc to usage.
10
+
11
+ [jeckyl-0.2.2 21-Sep-2012]
12
+
13
+ Add readme command to jeckyl to display README.md (when included properly)
14
+
7
15
  [jeckyl-0.2.1 20-Sep-2012]
8
16
 
9
17
  Tidy up documentation.
data/Intro.txt CHANGED
@@ -1,5 +1,7 @@
1
- Jeckyl can be used to create a parameters hash from a simple config file written in Ruby, having run whatever checks you want
2
- on the file to ensure the values passed in are valid. All you need to do is define a class inheriting from Jeckyl, methods for
1
+ Create and manage configuration files in Ruby for Ruby. Jeckyl can be used to create a parameters hash
2
+ from a simple config file written in Ruby, having run whatever checks you want on the file to ensure
3
+ the values passed in are valid. All you need to do is define a class inheriting from Jeckyl, methods for
3
4
  each parameter, its default, whatever checking rules are appropriate and even a comment for generating templates etc.
4
5
  This is then used to parse a Ruby config file and create the parameters hash. Jeckyl
5
6
  comes complete with a utility to check a config file against a given class and to generate a default file for you to tailor.
7
+ Type 'jeckyl readme' for more information.
data/README.md ADDED
@@ -0,0 +1,357 @@
1
+ #JECKYL
2
+
3
+ ### (a.k.a. Jumpin' Ermin's Configurator for Kwick and easY Linux services)
4
+
5
+ Jeckyl can be used to create a parameters hash from a simple config file written in Ruby, having run whatever checks you want
6
+ on the file to ensure the values passed in are valid. All you need to do is define a class inheriting from Jeckyl, methods for
7
+ each parameter, its default, whatever checking rules are appropriate and even a comment for generating templates etc.
8
+ This is then used to parse a Ruby config file and create the parameters hash. Jeckyl
9
+ comes complete with a utility to check a config file against a given class and to generate a default file for you to tailor.
10
+
11
+ Jeckyl was inspired by the configuration file methods in [Unicorn](http://unicorn.bogomips.org/).
12
+
13
+ ## Installation
14
+
15
+ Jeckyl comes as a gem. It can be installed in the usual way:
16
+
17
+ gem install jeckyl
18
+
19
+ That is all you need to do.
20
+
21
+ ## Getting Started
22
+
23
+ To use Jeckyl, create a new parameter class and add a parameter method for each parameter you want to define in
24
+ your config files. Think of the name of a parameter and prefix this with `configure_`:
25
+
26
+ require 'jeckyl'
27
+
28
+ class MyConfig < Jeckyl::Config
29
+
30
+ def configure_my_greeting(greet)
31
+ default "Hello"
32
+ comment "Set the standard greeting for this application"
33
+
34
+ a_string(greet)
35
+ end
36
+ end
37
+
38
+ The parameter method first sets a default value to be used if no value is given at all in the config file. This is
39
+ optional. It then describes the parameter, which is used by `jeckyl` when generating a blank config or a markdown file. Finally
40
+ it runs a check on the given parameter to ensure it is a string. Note the name of the method that you use in the
41
+ config file itself would be just 'my_greeting' wheras the parameter method is 'configure_my_greeting'.
42
+
43
+ Jeckyl comes complete with a whole range of checking methods that can be used for defining parameters
44
+ (see {Jeckyl::Config} for details). These methods are handy because they handle errors transparently.
45
+ It is not necessary, however, to use them so long as the value returned by the parameter method is what
46
+ you want in your config hash.
47
+
48
+ To use this simple example, you can generate a config file with jeckyl:
49
+
50
+ $ jeckyl generate config lib/my_app/my_config.rb >test/conf.d/test.rb
51
+
52
+ This will produce something like:
53
+
54
+ # Set the standard greeting for this application
55
+ #my_greeting "Hello"
56
+
57
+ Which you could change to:
58
+
59
+ # Set the standard greeting for this application
60
+ my_greeting "Welcome"
61
+
62
+ And then, to use this config file to create the options hash:
63
+
64
+ require 'my_app/my_config'
65
+
66
+ options = MyConfig.new('test/conf.d/test.rb')
67
+
68
+ options.inspect => {:config_files=>['test/conf.d/test.rb'], :my_greeting=>'Welcome'}
69
+
70
+ ## Using Jeckyl
71
+
72
+ ### Example Parameter Methods
73
+
74
+ Some examples of different parameters are given here, taken from the Jelly::Config class, Jelly being
75
+ a jazzed-up ruby logger:
76
+
77
+ def configure_log_level(lvl)
78
+ default :system
79
+ comment "Controls the amount of logging done by Jelly",
80
+ "",
81
+ " * :system - standard message, plus log to syslog",
82
+ " * :verbose - more generous logging to help resolve problems",
83
+ " * :debug - usually used only for resolving problems during development",
84
+ ""
85
+
86
+ lvl_set = [:system, :verbose, :debug]
87
+ a_member_of(lvl, lvl_set)
88
+
89
+ end
90
+
91
+ This shows a multi-line comment, the comment method takes any number of arguments and outputs
92
+ them one per line. It also shows how to test that a key value is used that belongs to a set.
93
+
94
+
95
+ def configure_log_rotation(int)
96
+ default 2
97
+ comment "Number of log files to retain at any time, between 0 and 20"
98
+
99
+ a_type_of(int, Integer) && in_range(int, 0, 20)
100
+
101
+ end
102
+
103
+ This shows how multiple tests can be and'd together.
104
+
105
+ def configure_log_length(int)
106
+ default 1 #Mbyte
107
+ comment "Size of a log file (in MB) before switching to the next log, upto 20 MB"
108
+
109
+ a_type_of(int, Integer) && in_range(int, 1, 20)
110
+ int * 1024 * 1024
111
+ end
112
+
113
+ This shows how the return value can be computed from the input parameter if required.
114
+
115
+ This final example shows a complicated parameter method that accepts an options hash and can
116
+ be called multiple times:
117
+
118
+ def configure_sensors(options)
119
+ comment "Add a sensor to monitor etc. This can be called multiple times",
120
+ " ",
121
+ " Sensors must be defined with the following:",
122
+ " :device - name of a device previously added with add_device",
123
+ " :name - the name for this thermostat (e.g. name of the room being monitored)",
124
+ " ",
125
+ " Sensors can have the following options:",
126
+ " :slope - gradient of the residual error function for the given sensor, default 0.0",
127
+ " :intercept - from the residual error function, default 0.0",
128
+ " "
129
+
130
+ unless @sensors
131
+ @sensors = Array.new
132
+ end
133
+
134
+ # remember the sensor names
135
+ unless @names
136
+ @names = Array.new
137
+ end
138
+
139
+ unless options.has_key?(:device)
140
+ raise Jeckyl::ConfigError, "You must supply a :device for each sensor"
141
+ end
142
+ unless @devices.include?(options[:device])
143
+ raise Jeckyl::ConfigError, "You must name a device that has already been added"
144
+ end
145
+ unless options.has_key?(:name)
146
+ raise Jeckyl::ConfigError, "You must supply a :name for each sensor"
147
+ end
148
+ @sensors.each do |sensor|
149
+ raise Jeckyl::ConfirError, "Each name must be unique" if sensor[:name] == options[:name]
150
+ end
151
+ a_type_of(options[:name], String)
152
+
153
+ raise Jeckyl::ConfigError, "You must supply an index" unless options.has_key?(:index)
154
+ a_type_of(options[:index], Integer) && in_range(options[:index], 1, 4)
155
+
156
+ options[:slope] ||= 0.0
157
+ a_type_of(options[:slope], Float)
158
+
159
+ options[:intercept] ||= 0.0
160
+ a_type_of(options[:intercept], Float)
161
+
162
+ @names << options[:name]
163
+
164
+ @sensors << options # return the current array of sensors
165
+
166
+ end
167
+
168
+ The method uses its own instance variables to keep track of things over multiple calls and
169
+ returns the @sensors array so that the actual parameter returned from Jeckyl will be the last value
170
+ returned. It uses a mixture of jeckyl tests and explicit tests to ensure the parameters are correct.
171
+ If preferred, you can add custom helper methods to your parameter class in the same manner as {Jeckyl::Config}.
172
+
173
+ ### Writing Ruby
174
+
175
+ Because the config file is ruby, it can contain any valid ruby code to help construct your parameters,
176
+ which can be instances of complex classes if required. BUT this also means the code can do things you
177
+ might not have intended so some care is needed here!
178
+
179
+ One of the things you can add, if it helps, is your own checking method. Call it what you like, pass in the object
180
+ to check (and whatever else you need) and either return the item or raise an error if the checks fail. There
181
+ are two methods available: {Jeckyl::Config#raise_config_error} e.g. for defining a value
182
+ outside the required range and {Jeckyl::Config#raise_syntax_error} e.g. for defining a string where a number is required.
183
+
184
+ ### Can't be bothered? a more relaxed approach
185
+
186
+ If you are lazy and cannot be bothered with defining lots of methods, you can relax the parsing and checking and convert a
187
+ parameter file straight into an options hash. To relax checking, set the :relax option to true when creating the parameters hash.
188
+ Then any parameter value pairs in the config file will be converted to key-value pairs in the hash
189
+ without any checks at all. You obviously cannot do much with this approach but in simple cases it may be OK?
190
+
191
+ If you don't like having to prefix your parameter methods with 'configure_' you can set another prefix
192
+ by redefining the prefix method in your subclass to return something else:
193
+
194
+ def prefix
195
+ 'set' # could also be 'cf' if you find typing a bore
196
+ end
197
+
198
+ ### Managing Parameter Hashes
199
+
200
+ You can easily merge parameter files using the {Jeckyl::Config#merge} method:
201
+
202
+ config = MyConfig.new('/etc/system.rb')
203
+ config.merge(File.join(ENV[USER], '.my_config_.rb'))
204
+ config.merge('./.local_config_.rb')
205
+
206
+ Jeckyl includes a couple of methods to help sub-divide parameter hashes. To extract
207
+ all of the parameters from a hash that belong to a given Jeckyl class, use Class.intersection(hash) (see
208
+ {Jeckyl::Config.intersection}). And to remove all of the parameters from one config hash in another,
209
+ use conf.complement(hash) ({Jeckyl::Config#complement}).
210
+
211
+ For example, the Jelly logger defines a set of logging parameters in Jelly::Config. These may be inherited
212
+ by another service that adds its own parameters (such as Jerbil):
213
+
214
+ options = Jerbil::Config.new(my_conf)
215
+
216
+ log_opts = Jelly::Config.intersection(options)
217
+
218
+ jerb_opts = options.complement(log_opts)
219
+
220
+ ### Some Internal Methods
221
+
222
+
223
+ ### Jeckyl::Config < Hash
224
+
225
+ Finally, note that Jeckyl::Config is itself a subclass of Hash, and therefore Jeckyl config objects inherit
226
+ all hash methods as well!
227
+
228
+ ## The 'jeckyl' Command
229
+
230
+ Jeckyl comes with a simple script: bin/jeckyl to help in creating, checking and documenting parameters.
231
+
232
+ You can create a simple config class to start you off with:
233
+
234
+ $ jeckyl klass <name>
235
+
236
+ which will output a small template to stdout. By default this will inherit from {Jeckyl::Config} but
237
+ you can add another parent with, for example:
238
+
239
+ $ jeckyl klass MyService JerbilService::Config
240
+
241
+ Save the file and edit it to add your parameters as required. Once you have defined the config class,
242
+ you can generate a default config file for your application using:
243
+
244
+ $ jeckyl config path/to/config_class.rb
245
+
246
+ This will generate a config file on stdout for each of the parameters, with the comment defined in the
247
+ parameter method and the default value where defined. Defaults will be commented out. You can save this file and edit it
248
+ to create a new config file.
249
+
250
+ Where you have created a config class that inherits from another config class, you will probably want to create
251
+ a config file with all of the parameters in it. By default only the config class defined in the given file
252
+ will be generated. To generate all parameters add the -k (for concat) option:
253
+
254
+ $ jeckyl config path/to/config_class.rb -k
255
+
256
+ The resulting config file will be neatly divided into sections, one for each class, starting with the most
257
+ ancestral. If you want to know what config classes you have inherited, then try:
258
+
259
+ $ jeckyl list path/to/config_class.rb
260
+
261
+ This will output an indexed list of the classes available. If you wanted to generate a config file just for one class,
262
+ select it with the -C option and the index from the list:
263
+
264
+ $ jeckyl config path/to/config_class.rb -C 2
265
+
266
+ Once you have editted your config file you can check if it is OK:
267
+
268
+ $ jeckyl check path/to/config_class.rb path/to/config_file.rb
269
+
270
+ This will either display error messages or tell you that the config file is OK.
271
+
272
+ Having created a config class, you may want to document it. Given that each parameter is already described within
273
+ the parameter method, it would be inconvenient to have to copy these comments into ruby comments just to
274
+ help the various documentation tools around. Instead, you can generate a markdown file from the parameter methods
275
+ and then include this in your documentation:
276
+
277
+ $ jeckyl markdown path/to/config_class.rb
278
+
279
+ This task takes the same options as the config task. You can then include a reference or link to this file
280
+ in the header comment for your config class. The template generated above already has a yard @see directive.
281
+
282
+ # @see file:lib/project/config_comments.md
283
+
284
+
285
+ ## Code Walkthrough
286
+
287
+ Jeckyl is documented on [RubyDoc.info](http://rdoc.info/github/osburn-sharp/jeckyl/frames).
288
+
289
+ Jeckyl consists of a single class: {Jeckyl::Config}. When you create an instance of a subclass the following
290
+ happens (see {Jeckyl::Config#initialize}):
291
+
292
+ + all of the parameter methods are called by {Jeckyl::Config#get_defaults} to obtain their default values
293
+ (the {Jeckyl::Config#default default} method sets this in a hash)
294
+ and are called again with these default values to process them through whatever the parameter method defines. This
295
+ ensures, for example, that if the parameter is multiplied by 10 before being added to the config hash,
296
+ the default value is also multipled by 10.
297
+
298
+ + if no config file is provided, the default values are returned as the options hash. This is used, for example,
299
+ by the config {Jeckyl::Config.generate_config generator}.
300
+
301
+ + finally, the given config file (whose name is added to the hash) is evaluated so that the resulting parameters are
302
+ added, overriding any defaults or manually entered values.
303
+
304
+ All of this is done with just a little bit of meta-magic. When the config file is eval'ed the parameter names are eval'ed
305
+ in the context of the instance being created, but because the parameter methods are all prefixed with something (configure by default)
306
+ method_missing is called instead. This orchestrates the setting of parameters and collecting of results into the options
307
+ hash, passing the parameter values to the corresponding parameter method.
308
+
309
+ For example, a config file might contain:
310
+
311
+ # define a greeting for the application
312
+ greeting "Hello"
313
+
314
+ There is no greeting method, so method_missing is called instead. This remembers the name of the "missing" method (:greeting),
315
+ calls configure_greeting and stores the results in the instances hash. The main reason for doing this (as opposed to just
316
+ calling the method 'greeting') is to enable the evaluation of defaults and comments in the context of each parameter method.
317
+ All of this is private and therefore under the bonnet.
318
+
319
+ ## Dependencies
320
+
321
+ See the {file:Gemfile} for details of dependencies.
322
+
323
+ Tested on Ruby 1.8.7.
324
+
325
+ ## Testing Jeckyl
326
+
327
+ There is an rspec test file to test the whole thing (spec/jeckyl_spec.rb). It uses the test subclass in "../test" and
328
+ various config files in "../conf.d". There is another rspec file that tests the config_check function.
329
+
330
+
331
+ ## Why did I bother?
332
+
333
+ Having tried various config file solutions, I had ended up using yaml files, but i found
334
+ checking them very difficult because they are not very friendly and very sensitive to spacing
335
+ issues. In looking for yet another alternative, I came across the approach used by
336
+ Unicorn (the backend web machine I now use for Rails apps). I liked the concept but
337
+ thought it could be made more general, which resulted in Jeckyl.
338
+
339
+ ## Bugs etc
340
+
341
+ Details of bugs can be found in {file:Bugs.rdoc}
342
+
343
+ ## Author and Contact
344
+
345
+ I am Robert Sharp and you can contact me on [GitHub](http://github.com/osburn-sharp)
346
+
347
+ ## Copyright and Licence
348
+
349
+ Copyright (c) 2011-2012 Robert Sharp.
350
+
351
+ See {file:LICENCE.rdoc LICENCE} for details of the licence under which Jeckyl is released.
352
+
353
+ ## Warranty
354
+
355
+ This software is provided "as is" and without any express or implied
356
+ warranties, including, without limitation, the implied warranties of
357
+ merchantibility and fitness for a particular purpose.
data/bin/jeckyl CHANGED
@@ -34,6 +34,24 @@ class JeckylCLI < Thor
34
34
  puts "Useful tasks for managing Jeckyl config files."
35
35
  puts ""
36
36
  help
37
+ puts ""
38
+ puts "See Also:"
39
+ puts " README.md: (see jeckyl readme above)"
40
+ puts " GitHub: https://github.com/osburn-sharp/jeckyl"
41
+ puts " RubyDoc: http://rdoc.info/github/osburn-sharp/jeckyl/frames"
42
+ end
43
+
44
+ desc "readme", "display the readme file for the gem"
45
+ def readme
46
+ gem_spec = Gem::Specification.find_by_name('jeckyl')
47
+ readme_path = File.join(gem_spec.gem_dir, 'README.md')
48
+
49
+ File.open(readme_path) do |rfile|
50
+ rfile.each_line do |rline|
51
+ puts rline
52
+ end
53
+ end
54
+
37
55
  end
38
56
 
39
57
  desc "list", "list all the config classes involved in a given class"
@@ -1,13 +1,13 @@
1
1
  # Created by Jevoom
2
2
  #
3
- # 20-Sep-2012
4
- # Tidy up documentation.
3
+ # 21-Sep-2012
4
+ # Add references to online docs etc to usage.
5
5
 
6
6
  module Jeckyl
7
- # version set to 0.2.1
8
- Version = '0.2.1'
9
- # date set to 20-Sep-2012
10
- Version_Date = '20-Sep-2012'
11
- #ident string set to: jeckyl-0.2.1 20-Sep-2012
12
- Ident = 'jeckyl-0.2.1 20-Sep-2012'
7
+ # version set to 0.2.3
8
+ Version = '0.2.3'
9
+ # date set to 21-Sep-2012
10
+ Version_Date = '21-Sep-2012'
11
+ #ident string set to: jeckyl-0.2.3 21-Sep-2012
12
+ Ident = 'jeckyl-0.2.3 21-Sep-2012'
13
13
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeckyl
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
9
+ - 3
10
+ version: 0.2.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Dr Robert
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-09-20 00:00:00 Z
18
+ date: 2012-09-21 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  type: :runtime
@@ -46,11 +46,13 @@ dependencies:
46
46
  version_requirements: *id002
47
47
  prerelease: false
48
48
  description: |
49
- Jeckyl can be used to create a parameters hash from a simple config file written in Ruby, having run whatever checks you want
50
- on the file to ensure the values passed in are valid. All you need to do is define a class inheriting from Jeckyl, methods for
49
+ Create and manage configuration files in Ruby for Ruby. Jeckyl can be used to create a parameters hash
50
+ from a simple config file written in Ruby, having run whatever checks you want on the file to ensure
51
+ the values passed in are valid. All you need to do is define a class inheriting from Jeckyl, methods for
51
52
  each parameter, its default, whatever checking rules are appropriate and even a comment for generating templates etc.
52
53
  This is then used to parse a Ruby config file and create the parameters hash. Jeckyl
53
54
  comes complete with a utility to check a config file against a given class and to generate a default file for you to tailor.
55
+ Type 'jeckyl readme' for more information.
54
56
 
55
57
  email: robert@osburn-sharp.ath.cx
56
58
  executables:
@@ -63,12 +65,14 @@ extra_rdoc_files:
63
65
  - Intro.txt
64
66
  - LICENCE.rdoc
65
67
  - Gemfile
68
+ - README.md
66
69
  files:
67
70
  - History.txt
68
71
  - Bugs.rdoc
69
72
  - Intro.txt
70
73
  - LICENCE.rdoc
71
74
  - Gemfile
75
+ - README.md
72
76
  - lib/jeckyl/errors.rb
73
77
  - lib/jeckyl/version.rb
74
78
  - lib/jeckyl.rb
@@ -110,7 +114,7 @@ files:
110
114
  homepage:
111
115
  licenses:
112
116
  - Open Software Licence v3.0
113
- post_install_message:
117
+ post_install_message: Jeckyl is now installed. Type 'jeckyl' for help
114
118
  rdoc_options:
115
119
  - --main=README.rdoc
116
120
  require_paths: