jeckyl 0.2.5 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/lib/jeckyl.rb +548 -548
- data/lib/jeckyl/version.rb +8 -8
- metadata +4 -4
data/History.txt
CHANGED
@@ -4,6 +4,14 @@
|
|
4
4
|
|
5
5
|
== History
|
6
6
|
|
7
|
+
[jeckyl-0.2.7 15-Nov-2012]
|
8
|
+
|
9
|
+
Change base directory for configs to /etc/jerbil consistent with the main jerbil gem
|
10
|
+
|
11
|
+
[jeckyl-0.2.6 25-Oct-2012]
|
12
|
+
|
13
|
+
Revert to /etc/jermine while working through changes to over gems
|
14
|
+
|
7
15
|
[jeckyl-0.2.5 25-Oct-2012]
|
8
16
|
|
9
17
|
Clean up unwanted git files and update README links (e.g. rubydoc)
|
data/lib/jeckyl.rb
CHANGED
@@ -21,13 +21,13 @@ module Jeckyl
|
|
21
21
|
|
22
22
|
#default location for all config files
|
23
23
|
# @deprecated Use {Jeckyl.config_dir} instead
|
24
|
-
ConfigRoot = '/etc/
|
24
|
+
ConfigRoot = '/etc/jerbil'
|
25
25
|
|
26
26
|
# the default system location for jeckyl config file
|
27
27
|
#
|
28
28
|
# This location can be set with the environment variable JECKYL_CONFIG_DIR
|
29
29
|
def Jeckyl.config_dir
|
30
|
-
ENV['JECKYL_CONFIG_DIR'] || '/etc/
|
30
|
+
ENV['JECKYL_CONFIG_DIR'] || '/etc/jerbil'
|
31
31
|
end
|
32
32
|
|
33
33
|
# This is the main Jeckyl class from which to create specific application
|
@@ -38,584 +38,584 @@ module Jeckyl
|
|
38
38
|
# More details are available in the {file:README.md Readme} file
|
39
39
|
class Config < Hash
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
41
|
+
# create a configuration hash by evaluating the parameters defined in the given config file.
|
42
|
+
#
|
43
|
+
# @param [String] config_file string path to a ruby file,
|
44
|
+
# @param [Hash] opts contains the following options.
|
45
|
+
# @option opts [Boolean] :flag_errors_on_defaults will raise exceptions from checks during default
|
46
|
+
# evaluation - although why is not clear, so best not to use it.
|
47
|
+
# @option opts [Boolean] :local limits generated defaults to the direct class being evaluated
|
48
|
+
# and should only be set internally on this call
|
49
|
+
# @option opts [Boolean] :relax, if set to true will not check for parameter methods but instead
|
50
|
+
# add unknown methods to the hash unchecked.
|
51
|
+
#
|
52
|
+
# If no config file is given then the hash of options returned will only have
|
53
|
+
# the defaults defined for the given class.
|
54
|
+
#
|
55
|
+
#
|
56
|
+
def initialize(config_file=nil, opts={})
|
57
|
+
# do whatever a hash has to do
|
58
|
+
super()
|
59
|
+
|
60
|
+
flag_errors_on_defaults = opts[:flag_errors_on_defaults] || false
|
61
|
+
local = opts[:local] || false
|
62
|
+
@_relax = opts[:relax] || false
|
59
63
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
self[:config_files] = [config_file]
|
64
|
+
# somewhere to save the most recently set symbol
|
65
|
+
@_last_symbol = nil
|
66
|
+
# hash for comments accessed with the same symbol
|
67
|
+
@_comments = {}
|
68
|
+
# hash for input defaults
|
69
|
+
@_defaults={}
|
70
|
+
# save order in which methods are defined for generating config files
|
71
|
+
@_order = Array.new
|
72
|
+
|
73
|
+
# get the defaults defined in the config parser
|
74
|
+
get_defaults(:local=> local, :flag_errors => flag_errors_on_defaults)
|
75
|
+
|
76
|
+
return self if config_file.nil?
|
77
|
+
|
78
|
+
# remember where the config file itself is
|
79
|
+
self[:config_files] = [config_file]
|
80
|
+
|
81
|
+
# and finally get the values from the config file itself
|
82
|
+
self.instance_eval(File.read(config_file), config_file)
|
80
83
|
|
81
|
-
# and finally get the values from the config file itself
|
82
|
-
self.instance_eval(File.read(config_file), config_file)
|
83
|
-
|
84
|
-
rescue SyntaxError => err
|
85
|
-
raise ConfigSyntaxError, err.message
|
86
|
-
rescue Errno::ENOENT
|
87
|
-
# duff file path so tell the caller
|
88
|
-
raise ConfigFileMissing, "#{config_file}"
|
89
|
-
end
|
90
|
-
|
91
|
-
# gives access to a hash containing an entry for each parameter and the comments
|
92
|
-
# defined by the class definitions - used internally by class methods
|
93
|
-
def comments
|
94
|
-
@_comments
|
95
|
-
end
|
96
|
-
|
97
|
-
# This contains an array of the parameter names - used internally by class methods
|
98
|
-
def order
|
99
|
-
@_order
|
100
|
-
end
|
101
|
-
|
102
|
-
# this contains a hash of the defaults for each parameter - used internally by class methods
|
103
|
-
def defaults
|
104
|
-
@_defaults
|
105
|
-
end
|
106
|
-
|
107
|
-
# a class method to check a given config file one item at a time
|
108
|
-
#
|
109
|
-
# This evaluates the given config file and reports if there are any errors to the
|
110
|
-
# report_file, which defaults to Stdout. Can only do the checking one error at a time.
|
111
|
-
#
|
112
|
-
# To use this method, it is necessary to write a script that calls it for the particular
|
113
|
-
# subclass.
|
114
|
-
#
|
115
|
-
# @param [String] config_file is the file to check
|
116
|
-
# @param [String] report_file is a file to write the report to, or stdout
|
117
|
-
# @return [Boolean] indicates if the check was OK or not
|
118
|
-
#
|
119
|
-
def self.check_config(config_file, report_file=nil)
|
120
|
-
|
121
|
-
# create myself to generate defaults, but nothing else
|
122
|
-
me = self.new
|
123
|
-
|
124
|
-
success = true
|
125
|
-
message = "No errors found in: #{config_file}"
|
126
|
-
|
127
|
-
begin
|
128
|
-
# evaluate the config file
|
129
|
-
me.instance_eval(File.read(config_file), config_file)
|
130
|
-
|
131
|
-
rescue Errno::ENOENT
|
132
|
-
message = "No such config file: #{config_file}"
|
133
|
-
success = false
|
134
|
-
rescue JeckylError => err
|
135
|
-
message = err.message
|
136
|
-
success = false
|
137
84
|
rescue SyntaxError => err
|
138
|
-
|
139
|
-
|
85
|
+
raise ConfigSyntaxError, err.message
|
86
|
+
rescue Errno::ENOENT
|
87
|
+
# duff file path so tell the caller
|
88
|
+
raise ConfigFileMissing, "#{config_file}"
|
140
89
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
90
|
+
|
91
|
+
# gives access to a hash containing an entry for each parameter and the comments
|
92
|
+
# defined by the class definitions - used internally by class methods
|
93
|
+
def comments
|
94
|
+
@_comments
|
95
|
+
end
|
96
|
+
|
97
|
+
# This contains an array of the parameter names - used internally by class methods
|
98
|
+
def order
|
99
|
+
@_order
|
100
|
+
end
|
101
|
+
|
102
|
+
# this contains a hash of the defaults for each parameter - used internally by class methods
|
103
|
+
def defaults
|
104
|
+
@_defaults
|
105
|
+
end
|
106
|
+
|
107
|
+
# a class method to check a given config file one item at a time
|
108
|
+
#
|
109
|
+
# This evaluates the given config file and reports if there are any errors to the
|
110
|
+
# report_file, which defaults to Stdout. Can only do the checking one error at a time.
|
111
|
+
#
|
112
|
+
# To use this method, it is necessary to write a script that calls it for the particular
|
113
|
+
# subclass.
|
114
|
+
#
|
115
|
+
# @param [String] config_file is the file to check
|
116
|
+
# @param [String] report_file is a file to write the report to, or stdout
|
117
|
+
# @return [Boolean] indicates if the check was OK or not
|
118
|
+
#
|
119
|
+
def self.check_config(config_file, report_file=nil)
|
120
|
+
|
121
|
+
# create myself to generate defaults, but nothing else
|
122
|
+
me = self.new
|
123
|
+
|
124
|
+
success = true
|
125
|
+
message = "No errors found in: #{config_file}"
|
126
|
+
|
127
|
+
begin
|
128
|
+
# evaluate the config file
|
129
|
+
me.instance_eval(File.read(config_file), config_file)
|
130
|
+
|
131
|
+
rescue Errno::ENOENT
|
132
|
+
message = "No such config file: #{config_file}"
|
133
|
+
success = false
|
134
|
+
rescue JeckylError => err
|
135
|
+
message = err.message
|
136
|
+
success = false
|
137
|
+
rescue SyntaxError => err
|
138
|
+
message = err.message
|
139
|
+
success = false
|
140
|
+
end
|
141
|
+
|
142
|
+
begin
|
143
|
+
if report_file.nil? then
|
144
|
+
puts message
|
145
|
+
else
|
146
|
+
File.open(report_file, "w") do |rfile|
|
147
|
+
rfile.puts message
|
148
|
+
end
|
148
149
|
end
|
150
|
+
return success
|
151
|
+
rescue Errno::ENOENT
|
152
|
+
raise ReportFileError, "Error with file: #{report_file}"
|
149
153
|
end
|
150
|
-
|
151
|
-
rescue Errno::ENOENT
|
152
|
-
raise ReportFileError, "Error with file: #{report_file}"
|
154
|
+
|
153
155
|
end
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
puts "# #{comment}"
|
156
|
+
|
157
|
+
# a class method to generate a config file from the class definition
|
158
|
+
#
|
159
|
+
# This calls each of the parameter methods, and creates a commented template
|
160
|
+
# with the comments and default lines
|
161
|
+
#
|
162
|
+
# @param [Boolean] local when set to true will limit the parameters to those defined in the
|
163
|
+
# immediate class and excludes any ancestors.
|
164
|
+
#
|
165
|
+
def self.generate_config(local=false)
|
166
|
+
me = self.new(nil, :local => local)
|
167
|
+
# everything should now exist
|
168
|
+
me.order.each do |key|
|
169
|
+
|
170
|
+
if me.comments.has_key?(key) then
|
171
|
+
me.comments[key].each do |comment|
|
172
|
+
puts "# #{comment}"
|
173
|
+
end
|
173
174
|
end
|
175
|
+
def_value = me.defaults[key]
|
176
|
+
default = def_value.nil? ? '' : def_value.inspect
|
177
|
+
|
178
|
+
puts "##{key.to_s} #{default}"
|
179
|
+
puts ""
|
174
180
|
end
|
175
|
-
def_value = me.defaults[key]
|
176
|
-
default = def_value.nil? ? '' : def_value.inspect
|
177
|
-
|
178
|
-
puts "##{key.to_s} #{default}"
|
179
|
-
puts ""
|
180
181
|
end
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
182
|
+
|
183
|
+
# extract only those parameters in a hash that are from the given class
|
184
|
+
#
|
185
|
+
# @param [Hash] full_config is the config from which to extract the intersecting options
|
186
|
+
# and it can be an instance of Jeckyl::Config or a hash
|
187
|
+
# @return [Hash] containing all of the intersecting parameters
|
188
|
+
#
|
189
|
+
# @note this returns a plain hash and not an instance of Jeckyl::Config
|
190
|
+
#
|
191
|
+
def self.intersection(full_config)
|
192
|
+
me = self.new # create the defaults for this class
|
193
|
+
my_hash = {}
|
194
|
+
me.order.each do |my_key|
|
195
|
+
if full_config.has_key?(my_key) then
|
196
|
+
my_hash[my_key] = full_config[my_key]
|
197
|
+
end
|
197
198
|
end
|
199
|
+
return my_hash
|
198
200
|
end
|
199
|
-
return my_hash
|
200
|
-
end
|
201
|
-
|
202
|
-
# return a list of descendant classes in the current context. This is provided to help
|
203
|
-
# find classes for the jeckyl utility, e.g. to generate a default config file
|
204
|
-
#
|
205
|
-
# @return [Array] classes that are descendants of this class, sorted with the least ancestral
|
206
|
-
# first
|
207
|
-
#
|
208
|
-
def self.descendants
|
209
|
-
descs = Array.new
|
210
|
-
ObjectSpace.each_object {|obj| descs << obj if obj.kind_of?(Class) && obj < self}
|
211
|
-
descs.sort! {|a,b| a < b ? -1 : 1}
|
212
|
-
return descs
|
213
|
-
end
|
214
|
-
|
215
|
-
|
216
|
-
# set the prefix to the parameter names that should be used for corresponding
|
217
|
-
# parameter methods defined for a subclass. Parameter names in config files
|
218
|
-
# are mapped onto parameter method by prefixing the methods with the results of
|
219
|
-
# this function. So, for a parameter named 'greeting', the parameter method used
|
220
|
-
# to check the parameter will be, by default, 'configure_greeting'.
|
221
|
-
#
|
222
|
-
# For example, to define parameter methods prefix with 'set' redefine this
|
223
|
-
# method to return 'set'. The greeting parameter method should then be called
|
224
|
-
# 'set_greeting'
|
225
|
-
#
|
226
|
-
def prefix
|
227
|
-
'configure'
|
228
|
-
end
|
229
|
-
|
230
|
-
# Delete those parameters that are in the given hash from this instance of Jeckyl::Config.
|
231
|
-
# Useful for tailoring parameter sets to specific uses (e.g. removing logging parameters)
|
232
|
-
#
|
233
|
-
# @param [Hash] conf_to_remove which is a hash or an instance of Jeckyl::Config
|
234
|
-
#
|
235
|
-
def complement(conf_to_remove)
|
236
|
-
self.delete_if {|key, value| conf_to_remove.has_key?(key)}
|
237
|
-
end
|
238
|
-
|
239
|
-
# Read, check and merge another parameter file into this one, being of the same config class.
|
240
|
-
#
|
241
|
-
# @param [String] conf_file - path to file to parse
|
242
|
-
#
|
243
|
-
def merge(conf_file)
|
244
201
|
|
245
|
-
|
202
|
+
# return a list of descendant classes in the current context. This is provided to help
|
203
|
+
# find classes for the jeckyl utility, e.g. to generate a default config file
|
204
|
+
#
|
205
|
+
# @return [Array] classes that are descendants of this class, sorted with the least ancestral
|
206
|
+
# first
|
207
|
+
#
|
208
|
+
def self.descendants
|
209
|
+
descs = Array.new
|
210
|
+
ObjectSpace.each_object {|obj| descs << obj if obj.kind_of?(Class) && obj < self}
|
211
|
+
descs.sort! {|a,b| a < b ? -1 : 1}
|
212
|
+
return descs
|
213
|
+
end
|
246
214
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
#
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
# create a description for the current parameter, to be used when generating a config template
|
261
|
-
#
|
262
|
-
# @param [*String] being one or more string arguments that are used to generate config file templates
|
263
|
-
# and documents
|
264
|
-
def comment(*strings)
|
265
|
-
@_comments[@_last_symbol] = strings unless @_last_symbol.nil?
|
266
|
-
end
|
267
|
-
|
268
|
-
# set default value(s) for the current parameter.
|
269
|
-
#
|
270
|
-
# @param [Object] val - any valid object as expected by the parameter method
|
271
|
-
def default(val)
|
272
|
-
return if @_last_symbol.nil? || @_defaults.has_key?(@_last_symbol)
|
273
|
-
@_defaults[@_last_symbol] = val
|
274
|
-
end
|
275
|
-
|
276
|
-
# the following are all helper methods to parse values and raise exceptions if the values are not correct
|
277
|
-
|
278
|
-
# file helpers - meanings should be apparent
|
279
|
-
|
280
|
-
# check that the parameter is a directory and that the directory is writable
|
281
|
-
#
|
282
|
-
# Jeckyl checking method to be used in parameter methods to check the validity of
|
283
|
-
# given parameters, returning the parameter if valid or else raising an exception
|
284
|
-
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
285
|
-
# the parameter is not validly formed
|
286
|
-
#
|
287
|
-
# @param [String] - path
|
288
|
-
#
|
289
|
-
def a_writable_dir(path)
|
290
|
-
if FileTest.directory?(path) && FileTest.writable?(path) then
|
291
|
-
path
|
292
|
-
else
|
293
|
-
raise_config_error(path, "directory is not writable or does not exist")
|
215
|
+
|
216
|
+
# set the prefix to the parameter names that should be used for corresponding
|
217
|
+
# parameter methods defined for a subclass. Parameter names in config files
|
218
|
+
# are mapped onto parameter method by prefixing the methods with the results of
|
219
|
+
# this function. So, for a parameter named 'greeting', the parameter method used
|
220
|
+
# to check the parameter will be, by default, 'configure_greeting'.
|
221
|
+
#
|
222
|
+
# For example, to define parameter methods prefix with 'set' redefine this
|
223
|
+
# method to return 'set'. The greeting parameter method should then be called
|
224
|
+
# 'set_greeting'
|
225
|
+
#
|
226
|
+
def prefix
|
227
|
+
'configure'
|
294
228
|
end
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
#
|
304
|
-
# @param [String] - path to file
|
305
|
-
#
|
306
|
-
def a_readable_file(path)
|
307
|
-
if FileTest.readable?(path) then
|
308
|
-
path
|
309
|
-
else
|
310
|
-
raise_config_error(path, "file does not exist")
|
229
|
+
|
230
|
+
# Delete those parameters that are in the given hash from this instance of Jeckyl::Config.
|
231
|
+
# Useful for tailoring parameter sets to specific uses (e.g. removing logging parameters)
|
232
|
+
#
|
233
|
+
# @param [Hash] conf_to_remove which is a hash or an instance of Jeckyl::Config
|
234
|
+
#
|
235
|
+
def complement(conf_to_remove)
|
236
|
+
self.delete_if {|key, value| conf_to_remove.has_key?(key)}
|
311
237
|
end
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
else
|
330
|
-
raise_config_error(obj, "value is not of required type: #{type}")
|
238
|
+
|
239
|
+
# Read, check and merge another parameter file into this one, being of the same config class.
|
240
|
+
#
|
241
|
+
# @param [String] conf_file - path to file to parse
|
242
|
+
#
|
243
|
+
def merge(conf_file)
|
244
|
+
|
245
|
+
self[:config_files] << conf_file
|
246
|
+
|
247
|
+
# get the values from the config file itself
|
248
|
+
self.instance_eval(File.read(conf_file), conf_file)
|
249
|
+
|
250
|
+
rescue SyntaxError => err
|
251
|
+
raise ConfigSyntaxError, err.message
|
252
|
+
rescue Errno::ENOENT
|
253
|
+
# duff file path so tell the caller
|
254
|
+
raise ConfigFileMissing, "#{conf_file}"
|
331
255
|
end
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
# @param [Numeric] lower bound of range
|
343
|
-
# @param [Numeric] upper bound of range
|
344
|
-
#
|
345
|
-
def in_range(val, lower, upper)
|
346
|
-
raise_syntax_error("#{lower.to_s}..#{upper.to_s} is not a range") unless (lower .. upper).kind_of?(Range)
|
347
|
-
if (lower .. upper) === val then
|
348
|
-
val
|
349
|
-
else
|
350
|
-
raise_config_error(val, "value is not within required range: #{lower.to_s}..#{upper.to_s}")
|
256
|
+
|
257
|
+
|
258
|
+
protected
|
259
|
+
|
260
|
+
# create a description for the current parameter, to be used when generating a config template
|
261
|
+
#
|
262
|
+
# @param [*String] being one or more string arguments that are used to generate config file templates
|
263
|
+
# and documents
|
264
|
+
def comment(*strings)
|
265
|
+
@_comments[@_last_symbol] = strings unless @_last_symbol.nil?
|
351
266
|
end
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
# Jeckyl checking method to be used in parameter methods to check the validity of
|
360
|
-
# given parameters, returning the parameter if valid or else raising an exception
|
361
|
-
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
362
|
-
# the parameter is not validly formed
|
363
|
-
#
|
364
|
-
# @param [Boolean] val to check
|
365
|
-
#
|
366
|
-
def a_boolean(val)
|
367
|
-
if val.kind_of?(TrueClass) || val.kind_of?(FalseClass) then
|
368
|
-
val
|
369
|
-
else
|
370
|
-
raise_config_error(val, "Value is not a Boolean")
|
267
|
+
|
268
|
+
# set default value(s) for the current parameter.
|
269
|
+
#
|
270
|
+
# @param [Object] val - any valid object as expected by the parameter method
|
271
|
+
def default(val)
|
272
|
+
return if @_last_symbol.nil? || @_defaults.has_key?(@_last_symbol)
|
273
|
+
@_defaults[@_last_symbol] = val
|
371
274
|
end
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
raise_config_error(val, "Cannot convert to Boolean")
|
275
|
+
|
276
|
+
# the following are all helper methods to parse values and raise exceptions if the values are not correct
|
277
|
+
|
278
|
+
# file helpers - meanings should be apparent
|
279
|
+
|
280
|
+
# check that the parameter is a directory and that the directory is writable
|
281
|
+
#
|
282
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
283
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
284
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
285
|
+
# the parameter is not validly formed
|
286
|
+
#
|
287
|
+
# @param [String] - path
|
288
|
+
#
|
289
|
+
def a_writable_dir(path)
|
290
|
+
if FileTest.directory?(path) && FileTest.writable?(path) then
|
291
|
+
path
|
292
|
+
else
|
293
|
+
raise_config_error(path, "directory is not writable or does not exist")
|
294
|
+
end
|
393
295
|
end
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
ary
|
411
|
-
else
|
412
|
-
raise_config_error(ary, "value is not an Array")
|
296
|
+
|
297
|
+
# check parameter is a readable file
|
298
|
+
#
|
299
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
300
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
301
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
302
|
+
# the parameter is not validly formed
|
303
|
+
#
|
304
|
+
# @param [String] - path to file
|
305
|
+
#
|
306
|
+
def a_readable_file(path)
|
307
|
+
if FileTest.readable?(path) then
|
308
|
+
path
|
309
|
+
else
|
310
|
+
raise_config_error(path, "file does not exist")
|
311
|
+
end
|
413
312
|
end
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
313
|
+
|
314
|
+
# simple type helpers
|
315
|
+
|
316
|
+
# check the parameter is of the required type
|
317
|
+
#
|
318
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
319
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
320
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
321
|
+
# the parameter is not validly formed
|
322
|
+
#
|
323
|
+
# @param [Object] obj to check type of
|
324
|
+
# @param [Class] type, being a class constant such as Numeric, String
|
325
|
+
#
|
326
|
+
def a_type_of(obj, type)
|
327
|
+
if obj.kind_of?(type) then
|
328
|
+
obj
|
329
|
+
else
|
330
|
+
raise_config_error(obj, "value is not of required type: #{type}")
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# check that the parameter is within the required range
|
335
|
+
#
|
336
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
337
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
338
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
339
|
+
# the parameter is not validly formed
|
340
|
+
#
|
341
|
+
# @param [Numeric] val to check
|
342
|
+
# @param [Numeric] lower bound of range
|
343
|
+
# @param [Numeric] upper bound of range
|
344
|
+
#
|
345
|
+
def in_range(val, lower, upper)
|
346
|
+
raise_syntax_error("#{lower.to_s}..#{upper.to_s} is not a range") unless (lower .. upper).kind_of?(Range)
|
347
|
+
if (lower .. upper) === val then
|
348
|
+
val
|
349
|
+
else
|
350
|
+
raise_config_error(val, "value is not within required range: #{lower.to_s}..#{upper.to_s}")
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
|
355
|
+
# boolean helpers
|
356
|
+
|
357
|
+
# check parameter is a boolean, true or false but not strings "true" or "false"
|
358
|
+
#
|
359
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
360
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
361
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
362
|
+
# the parameter is not validly formed
|
363
|
+
#
|
364
|
+
# @param [Boolean] val to check
|
365
|
+
#
|
366
|
+
def a_boolean(val)
|
367
|
+
if val.kind_of?(TrueClass) || val.kind_of?(FalseClass) then
|
368
|
+
val
|
369
|
+
else
|
370
|
+
raise_config_error(val, "Value is not a Boolean")
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
# check the parameter is a flag, being "true", "false", "yes", "no", "on", "off", or 1 , 0
|
375
|
+
# and return a proper boolean
|
376
|
+
#
|
377
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
378
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
379
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
380
|
+
# the parameter is not validly formed
|
381
|
+
#
|
382
|
+
# @param [String] val to check
|
383
|
+
#
|
384
|
+
def a_flag(val)
|
385
|
+
val = val.downcase if val.kind_of?(String)
|
386
|
+
case val
|
387
|
+
when "true", "yes", "on", 1
|
388
|
+
true
|
389
|
+
when "false", "no", "off", 0
|
390
|
+
false
|
391
|
+
else
|
392
|
+
raise_config_error(val, "Cannot convert to Boolean")
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
|
397
|
+
# compound objects
|
398
|
+
|
399
|
+
# check the parameter is an array
|
400
|
+
#
|
401
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
402
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
403
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
404
|
+
# the parameter is not validly formed
|
405
|
+
#
|
406
|
+
# @param [Array] ary to check
|
407
|
+
#
|
408
|
+
def an_array(ary)
|
409
|
+
if ary.kind_of?(Array) then
|
410
|
+
ary
|
411
|
+
else
|
412
|
+
raise_config_error(ary, "value is not an Array")
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# check the parameter is an array and the array is of the required type
|
417
|
+
#
|
418
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
419
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
420
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
421
|
+
# the parameter is not validly formed
|
422
|
+
#
|
423
|
+
# @param [Array] ary of values to check
|
424
|
+
# @param [Class] type being the class that the values must belong to
|
425
|
+
#
|
426
|
+
def an_array_of(ary, type)
|
427
|
+
raise_syntax_error("Provided a value that is a type: #{type.to_s}") unless type.class == Class
|
428
|
+
if ary.kind_of?(Array) then
|
429
|
+
ary.each do |element|
|
430
|
+
unless element.kind_of?(type) then
|
431
|
+
raise_config_error(element, "element of array is not of type: #{type}")
|
432
|
+
end
|
432
433
|
end
|
434
|
+
return ary
|
435
|
+
else
|
436
|
+
raise_config_error(ary, "value is not an Array")
|
433
437
|
end
|
434
|
-
return ary
|
435
|
-
else
|
436
|
-
raise_config_error(ary, "value is not an Array")
|
437
438
|
end
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
439
|
+
|
440
|
+
# check the parameter is a hash
|
441
|
+
#
|
442
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
443
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
444
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
445
|
+
# the parameter is not validly formed
|
446
|
+
#
|
447
|
+
# @param [Hash] hsh to check
|
448
|
+
#
|
449
|
+
def a_hash(hsh)
|
450
|
+
if hsh.kind_of?(Hash) then
|
451
|
+
true
|
452
|
+
else
|
453
|
+
raise_config_error(hsh, "value is not a Hash")
|
454
|
+
end
|
454
455
|
end
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
456
|
+
|
457
|
+
# strings and text and stuff
|
458
|
+
|
459
|
+
# check the parameter is a string
|
460
|
+
#
|
461
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
462
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
463
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
464
|
+
# the parameter is not validly formed
|
465
|
+
#
|
466
|
+
# @param [String] str to check
|
467
|
+
#
|
468
|
+
def a_string(str)
|
469
|
+
if str.kind_of?(String) then
|
470
|
+
str
|
471
|
+
else
|
472
|
+
raise_config_error(str.to_s, "is not a String")
|
473
|
+
end
|
473
474
|
end
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
475
|
+
|
476
|
+
# check the parameter is a string and matches the required pattern
|
477
|
+
#
|
478
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
479
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
480
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
481
|
+
# the parameter is not validly formed
|
482
|
+
#
|
483
|
+
# @param [String] str to match against the pattern
|
484
|
+
# @param [Regexp] pattern to match with
|
485
|
+
#
|
486
|
+
def a_matching_string(str, pattern)
|
487
|
+
raise_syntax_error("Attempt to pattern match without a Regexp") unless pattern.kind_of?(Regexp)
|
488
|
+
if pattern =~ a_string(str) then
|
489
|
+
str
|
490
|
+
else
|
491
|
+
raise_config_error(str, "does not match required pattern: #{pattern.source}")
|
492
|
+
end
|
492
493
|
end
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
494
|
+
|
495
|
+
# set membership - set is an array of members, usually symbols
|
496
|
+
#
|
497
|
+
# Jeckyl checking method to be used in parameter methods to check the validity of
|
498
|
+
# given parameters, returning the parameter if valid or else raising an exception
|
499
|
+
# which is either ConfigError if the parameter fails the check or ConfigSyntaxError if
|
500
|
+
# the parameter is not validly formed
|
501
|
+
#
|
502
|
+
# @param [Symbol] symb being the symbol to check
|
503
|
+
# @param [Array] set containing the valid symbols that symb should belong to
|
504
|
+
#
|
505
|
+
def a_member_of(symb, set)
|
506
|
+
raise_syntax_error("Sets to test membership must be arrays") unless set.kind_of?(Array)
|
507
|
+
if set.include?(symb) then
|
508
|
+
symb
|
509
|
+
else
|
510
|
+
raise_config_error(symb, "is not a member of: #{set.join(', ')}")
|
511
|
+
end
|
511
512
|
end
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
513
|
+
|
514
|
+
|
515
|
+
private
|
516
|
+
|
517
|
+
# decides what to do with parameters that have not been defined.
|
518
|
+
# unless @_relax then it will raise an exception. Otherwise it will create a key value pair
|
519
|
+
#
|
520
|
+
# This method also remembers the method name as the key to prevent the parsers etc from
|
521
|
+
# having to carry this around just to do things like report on it.
|
522
|
+
#
|
523
|
+
def method_missing(symb, parameter)
|
524
|
+
|
525
|
+
@_last_symbol = symb
|
526
|
+
#@parameter = parameter
|
527
|
+
method_to_call = ("#{self.prefix}_" + symb.to_s).to_sym
|
528
|
+
set_method = self.method(method_to_call)
|
529
|
+
|
530
|
+
self[@_last_symbol] = set_method.call(parameter)
|
531
|
+
|
532
|
+
rescue NameError
|
533
|
+
#raise if @@debug
|
534
|
+
# no parser method defined.
|
535
|
+
unless @_relax then
|
536
|
+
# not tolerable
|
537
|
+
raise UnknownParameter, format_error(symb, parameter, "Unknown parameter")
|
538
|
+
else
|
539
|
+
# feeling relaxed, so lets store it anyway.
|
540
|
+
self[symb] = parameter
|
541
|
+
end
|
542
|
+
|
541
543
|
end
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
# ignore any errors raised
|
544
|
+
|
545
|
+
# get_defaults
|
546
|
+
#
|
547
|
+
# calls each method with the specified prefix with no parameters so that the defaults
|
548
|
+
# defined for each will be passed back and used to set the hash before the
|
549
|
+
# config file is evaluated.
|
550
|
+
#
|
551
|
+
def get_defaults(opts={})
|
552
|
+
flag_errors = opts[:flag_errors]
|
553
|
+
local = opts[:local]
|
554
|
+
|
555
|
+
# go through all of the methods
|
556
|
+
self.class.instance_methods(!local).each do |method_name|
|
557
|
+
if md = /^#{self.prefix}_/.match(method_name) then
|
558
|
+
|
559
|
+
# its a prefixed method so call it
|
560
|
+
|
561
|
+
pref_method = self.method(method_name.to_sym)
|
562
|
+
# get the corresponding symbol for the hash
|
563
|
+
@_last_symbol = md.post_match.to_sym
|
564
|
+
@_order << @_last_symbol
|
565
|
+
# and call the method with no parameters, which will
|
566
|
+
# call the comment method and the default method where defined
|
567
|
+
# and thereby capture their values
|
568
|
+
begin
|
569
|
+
a_value = pref_method.call(1)
|
570
|
+
rescue Exception
|
571
|
+
# ignore any errors, which are bound to result from passing in 1
|
572
|
+
end
|
573
|
+
begin
|
574
|
+
# now set the actual default by calling the method again and passing
|
575
|
+
# the captured default, providing a result which may be different if the method transforms
|
576
|
+
# the parameter!
|
577
|
+
param = @_defaults[@_last_symbol]
|
578
|
+
self[@_last_symbol] = pref_method.call(param) unless param.nil?
|
579
|
+
rescue Exception
|
580
|
+
raise if flag_errors
|
581
|
+
# ignore any errors raised
|
582
|
+
end
|
582
583
|
end
|
583
584
|
end
|
584
585
|
end
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
end
|
586
|
+
|
587
|
+
# really private helpers that should not be needed unless the parser method
|
588
|
+
# is custom
|
589
|
+
|
590
|
+
protected
|
591
|
+
|
592
|
+
# helper method to format exception messages. A config error should be raised
|
593
|
+
# when the given parameter does not match the checks.
|
594
|
+
#
|
595
|
+
# The exception is raised in the caller's context to ensure backtraces are accurate.
|
596
|
+
#
|
597
|
+
# @param [Object] value - the object that caused the error
|
598
|
+
# @param [String] message to include in the exception
|
599
|
+
#
|
600
|
+
def raise_config_error(value, message)
|
601
|
+
raise ConfigError, format_error(@_last_symbol, value, message), caller
|
602
|
+
end
|
603
|
+
|
604
|
+
# helper method to format exception messages. A syntax error should be raised
|
605
|
+
# when the check method has been used incorrectly. See check methods for examples.
|
606
|
+
#
|
607
|
+
# The exception is raised in the caller's context to ensure backtraces are accurate.
|
608
|
+
#
|
609
|
+
# @param [String] message to include in the exception
|
610
|
+
#
|
611
|
+
def raise_syntax_error(message)
|
612
|
+
raise ConfigSyntaxError, message, caller
|
613
|
+
end
|
614
|
+
|
615
|
+
# helper method to format an error
|
616
|
+
def format_error(key, value, message)
|
617
|
+
"[#{key}]: #{value} - #{message}"
|
618
|
+
end
|
619
619
|
|
620
620
|
end
|
621
621
|
|
data/lib/jeckyl/version.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# Created by Jevoom
|
2
2
|
#
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# 15-Nov-2012
|
4
|
+
# Change base directory for configs to /etc/jerbil consistent with the main jerbil gem
|
5
5
|
|
6
6
|
module Jeckyl
|
7
|
-
# version set to 0.2.
|
8
|
-
Version = '0.2.
|
9
|
-
# date set to
|
10
|
-
Version_Date = '
|
11
|
-
#ident string set to: jeckyl-0.2.
|
12
|
-
Ident = 'jeckyl-0.2.
|
7
|
+
# version set to 0.2.7
|
8
|
+
Version = '0.2.7'
|
9
|
+
# date set to 15-Nov-2012
|
10
|
+
Version_Date = '15-Nov-2012'
|
11
|
+
#ident string set to: jeckyl-0.2.7 15-Nov-2012
|
12
|
+
Ident = 'jeckyl-0.2.7 15-Nov-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:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 7
|
10
|
+
version: 0.2.7
|
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-
|
18
|
+
date: 2012-11-15 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
type: :runtime
|