params 0.0.9 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/params.rb CHANGED
@@ -7,10 +7,12 @@
7
7
  #
8
8
  # Examples of definitions:
9
9
  # Params.string('parameter_str', 'this is a string' ,'description_for_string')
10
+ # Params.path('parameter_path', '/Users/username/example/ect' ,'description_for_directory')
10
11
  # Params.integer('parameter_int',1 , 'description_for_integer')
11
12
  # Params.float('parameter_float',2.6 , 'description_for_float')
12
13
  # Params.boolean('parameter_true', true, 'description_for_true')
13
14
  # Params.boolean('parameter_false',false , 'description_for_false')
15
+ # Params.complex('parameter_complex', [a,b,{b=>c}], 'description for dict or list of strings.')
14
16
  # Note. Parameters have to be defined before they are accessed.
15
17
  #
16
18
  # Examples of usages (get\set access is through the [] operator).
@@ -52,280 +54,363 @@
52
54
  # More examples in bbfs/examples/params/rb
53
55
 
54
56
  require 'optparse'
57
+ require 'stringio'
55
58
  require 'yaml'
56
59
 
57
- module BBFS
58
- module Params
59
-
60
- @init_debug_messages = []
61
- @help_messages = []
62
-
63
- def Params.get_init_messages
64
- return @init_debug_messages
65
- end
66
-
67
- # Represents a parameter.
68
- class Param
69
- attr_accessor :name
70
- attr_accessor :value
71
- attr_accessor :desc
72
- attr_accessor :type
73
-
74
- # value_type_check method:
75
- # 1. Check if member:'type' is one of:Integer, Float, String or Boolean.
76
- # 2. input parameter:'value' class type is valid to override this parameter.
77
- # 3. Return value. The value to override with correct type. A cast from integer to Float will
78
- # be made for Float parameters which are set with integer values.
79
- # 4. Check will be skipped for nil value.
80
- def value_type_check(value)
81
- if value.nil?
82
- return value
83
- end
60
+ module Params
61
+
62
+ @init_debug_messages = []
63
+ @show_help_and_exit = false
64
+
65
+ def Params.get_init_messages
66
+ return @init_debug_messages
67
+ end
68
+
69
+ # Represents a parameter.
70
+ class Param
71
+ attr_accessor :name
72
+ attr_accessor :value
73
+ attr_accessor :desc
74
+ attr_accessor :type
75
+
76
+ # value_type_check method:
77
+ # 1. Check if member:'type' is one of:Integer, Float, String or Boolean.
78
+ # 2. input parameter:'value' class type is valid to override this parameter.
79
+ # 3. Return value. The value to override with correct type. A cast from integer to Float will
80
+ # be made for Float parameters which are set with integer values.
81
+ # 4. Check will be skipped for nil value.
82
+ def value_type_check(value)
83
+ if value.nil?
84
+ return value
85
+ end
84
86
 
85
- case( @type )
86
- when 'Integer' then
87
- if not @value.nil?
88
- if not ((value.class.eql? Integer) or
89
- (value.class.eql? Fixnum))
90
- raise "Parameter:'#{@name}' type:'Integer' but value type to override " \
87
+ case( @type )
88
+ when 'Integer' then
89
+ if not @value.nil?
90
+ if not ((value.class.eql? Integer) or
91
+ (value.class.eql? Fixnum))
92
+ raise "Parameter:'#{@name}' type:'Integer' but value type to override " \
91
93
  "is:'#{value.class}'."
92
- end
93
94
  end
94
- when 'Float' then
95
- if not @value.nil?
96
- if not value.class.eql? Float
97
- if not ((value.class.eql? Integer) or
98
- (value.class.eql? Fixnum))
99
- raise("Parameter:'#{@name}' type:'Float' but value type to override " \
95
+ end
96
+ when 'Float' then
97
+ if not @value.nil?
98
+ if not value.class.eql? Float
99
+ if not ((value.class.eql? Integer) or
100
+ (value.class.eql? Fixnum))
101
+ raise("Parameter:'#{@name}' type:'Float' but value type to override " \
100
102
  "is:'#{value.class}'.")
101
- else
102
- return value.to_f
103
- end
103
+ else
104
+ return value.to_f
104
105
  end
105
106
  end
106
- when 'String' then
107
- if not @value.nil?
108
- if not value.class.eql? String
109
- raise("Parameter:'#{@name}' type:'String' but value type to override " \
107
+ end
108
+ when 'String' then
109
+ when 'Path' then
110
+ # TODO(kolman): Override the type check with regexp of path in Linux and/or Windows
111
+ if not @value.nil?
112
+ if not value.class.eql? String
113
+ raise("Parameter:'#{@name}' type:'String' but value type to override " \
110
114
  "is:'#{value.class}'.")
111
- end
112
115
  end
113
- when 'Boolean' then
114
- if not @value.nil?
115
- if not((value.class.eql? TrueClass) or (value.class.eql? FalseClass))
116
- raise("Parameter:'#{@name}' type:'Boolean' but value type to override " \
116
+ end
117
+ when 'Boolean' then
118
+ if not @value.nil?
119
+ if not((value.class.eql? TrueClass) or (value.class.eql? FalseClass))
120
+ raise("Parameter:'#{@name}' type:'Boolean' but value type to override " \
117
121
  "is:'#{value.class}'.")
118
- end
119
122
  end
120
- else
121
- raise("Parameter:'#{@name}' type:'#{@value.class}' but parameter " \
123
+ end
124
+ when 'Complex' then
125
+ unless @value.nil?
126
+ unless (value.class.eql? Hash) or (value.class.eql? Array)
127
+ raise("Parameter:'#{@name}' type:'Complex' but value type to override " \
128
+ "is:'#{value.class}'.")
129
+ end
130
+ end
131
+ else
132
+ raise("Parameter:'#{@name}' type:'#{@value.class}' but parameter " \
122
133
  "type to override:'#{value.class}' is not supported. " + \
123
134
  "Supported types are:Integer, Float, String or Boolean.")
124
- end
125
- return value
126
- end
127
-
128
- # supported types are: String, Integer, Float and Boolean
129
- def initialize(name, value, type, desc)
130
- @name = name
131
- @type = type
132
- @desc = desc
133
- @value = value_type_check value
134
135
  end
136
+ return value
135
137
  end
136
138
 
137
- # The globals data structure.
138
- @globals_db = Hash.new
139
-
140
- def Params.raise_error_if_param_does_not_exist(name)
141
- if not @globals_db[name]
142
- raise("before using parameter:'#{name}', it should first be defined through Param module methods:" \
143
- "Params.string, Params.integer, Params.float or Params.boolean.")
144
- end
139
+ # supported types are: String, Integer, Float, Boolean, Path or Complex
140
+ def initialize(name, value, type, desc)
141
+ @name = name
142
+ @type = type
143
+ @desc = desc
144
+ @value = value_type_check value
145
145
  end
146
+ end
146
147
 
147
- def Params.raise_error_if_param_exists(name)
148
- if @globals_db[name]
149
- raise("Parameter:'#{name}', can only be defined once.")
150
- end
151
- end
148
+ # The globals data structure.
149
+ @globals_db = Hash.new
152
150
 
153
- # Read global param value by other modules.
154
- # Note that this operator should only be used, after parameter has been defined through
155
- # one of Param module methods: Params.string, Params.integer,
156
- # Params.float or Params.boolean."
157
- def Params.[](name)
158
- raise_error_if_param_does_not_exist(name)
159
- @globals_db[name].value
151
+ def Params.raise_error_if_param_does_not_exist(name)
152
+ if not @globals_db[name]
153
+ raise("before using parameter:'#{name}', it should first be defined through Param module methods:" \
154
+ "Params.string, Params.path, Params.integer, Params.float or Params.boolean.")
160
155
  end
156
+ end
161
157
 
162
- # Write global param value by other modules.
163
- # Note that this operator should only be used, after parameter has been defined through
164
- # one of Param module methods: Params.string, Params.integer,
165
- # Params.float or Params.boolean."
166
- def Params.[]=(name, value)
167
- raise_error_if_param_does_not_exist(name)
168
- set_value = @globals_db[name].value_type_check(value)
169
- @globals_db[name].value = set_value
158
+ def Params.raise_error_if_param_exists(name)
159
+ if @globals_db[name]
160
+ raise("Parameter:'#{name}', can only be defined once.")
170
161
  end
171
-
172
- #override parameter should only be called by Params module methods.
173
- def Params.override_param(name, value)
174
- existing_param = @globals_db[name]
175
- if existing_param.nil?
176
- raise("Parameter:'#{name}' has not been defined and can not be overridden. " \
162
+ end
163
+
164
+ # Read global param value by other modules.
165
+ # Note that this operator should only be used, after parameter has been defined through
166
+ # one of Param module methods: Params.string, Params.integer,
167
+ # Params.float or Params.boolean."
168
+ def Params.[](name)
169
+ raise_error_if_param_does_not_exist(name)
170
+ @globals_db[name].value
171
+ end
172
+
173
+ def Params.each(&block)
174
+ @globals_db.each(&block)
175
+ end
176
+
177
+ # Write global param value by other modules.
178
+ # Note that this operator should only be used, after parameter has been defined through
179
+ # one of Param module methods: Params.string, Params.integer,
180
+ # Params.float or Params.boolean."
181
+ def Params.[]=(name, value)
182
+ raise_error_if_param_does_not_exist(name)
183
+ set_value = @globals_db[name].value_type_check(value)
184
+ @globals_db[name].value = set_value
185
+ end
186
+
187
+ #override parameter should only be called by Params module methods.
188
+ def Params.override_param(name, value)
189
+ existing_param = @globals_db[name]
190
+ if existing_param.nil?
191
+ raise("Parameter:'#{name}' has not been defined and can not be overridden. " \
177
192
  "It should first be defined through Param module methods:" \
178
- "Params.string, Params.integer, Params.float or Params.boolean.")
179
- end
180
- if value.nil?
181
- existing_param.value = nil
182
- elsif existing_param.type.eql?('String')
183
- existing_param.value = value.to_s
193
+ "Params.string, Params.path, Params.integer, Params.float or Params.boolean.")
194
+ end
195
+ if value.nil?
196
+ existing_param.value = nil
197
+ elsif existing_param.type.eql?('String')
198
+ existing_param.value = value.to_s
199
+ elsif existing_param.type.eql?('Path')
200
+ existing_param.value = File.expand_path(value.to_s)
201
+ elsif existing_param.type.eql?('Complex')
202
+ if value.class.eql?(Hash) || value.class.eql?(Array)
203
+ existing_param.value = value
184
204
  else
185
- set_value = existing_param.value_type_check(value)
186
- existing_param.value = set_value
205
+ existing_param.value = YAML::load(StringIO.new(value.to_s))
187
206
  end
207
+ else
208
+ set_value = existing_param.value_type_check(value)
209
+ existing_param.value = set_value
188
210
  end
189
-
190
- # Define new global parameter of type Integer.
191
- def Params.integer(name, value, description)
192
- raise_error_if_param_exists(name)
193
- @globals_db[name] = Param.new(name, value, 'Integer', description)
194
- end
195
-
196
- # Define new global parameter of type Float.
197
- def Params.float(name, value, description)
198
- raise_error_if_param_exists(name)
199
- @globals_db[name] = Param.new(name, value, 'Float', description)
200
- end
201
-
202
- # Define new global parameter of type String.
203
- def Params.string(name, value, description)
204
- raise_error_if_param_exists(name)
205
- @globals_db[name] = Param.new(name, value, 'String', description)
206
- end
207
-
208
- # Define new global parameter of type Boolean.
209
- def Params.boolean(name, value, description)
210
- raise_error_if_param_exists(name)
211
- @globals_db[name] = Param.new(name, value, 'Boolean', description)
211
+ end
212
+
213
+ # Define new global parameter of type Integer.
214
+ def Params.integer(name, value, description)
215
+ raise_error_if_param_exists(name)
216
+ @globals_db[name] = Param.new(name, value, 'Integer', description)
217
+ end
218
+
219
+ # Define new global parameter of type Float.
220
+ def Params.float(name, value, description)
221
+ raise_error_if_param_exists(name)
222
+ @globals_db[name] = Param.new(name, value, 'Float', description)
223
+ end
224
+
225
+ # Define new global parameter of type String.
226
+ def Params.string(name, value, description)
227
+ raise_error_if_param_exists(name)
228
+ @globals_db[name] = Param.new(name, value, 'String', description)
229
+ end
230
+
231
+ # Define new global parameter of type path (the only difference with string is that the path expends '~' to
232
+ # full user directory).
233
+ def Params.path(name, value, description)
234
+ raise_error_if_param_exists(name)
235
+ @globals_db[name] = Param.new(name, File.expand_path(value), 'Path', description)
236
+ end
237
+
238
+ def Params.complex(name, value, description)
239
+ raise_error_if_param_exists(name)
240
+ @globals_db[name] = Param.new(name, value, 'Complex', description)
241
+ end
242
+
243
+ # Define new global parameter of type Boolean.
244
+ def Params.boolean(name, value, description)
245
+ raise_error_if_param_exists(name)
246
+ @globals_db[name] = Param.new(name, value, 'Boolean', description)
247
+ end
248
+
249
+ # Initializes the project parameters.
250
+ # Precedence is: Defined params, file and command line is highest.
251
+ def Params.init(args)
252
+ @init_debug_messages = []
253
+ results = parse_command_line_arguments(args)
254
+ if not results['conf_file'].nil?
255
+ Params['conf_file'] = File.expand_path(results['conf_file'])
212
256
  end
213
257
 
214
- # Initializes the project parameters.
215
- # Precedence is: Defined params, file and command line is highest.
216
- def Params.init(args)
217
- @init_debug_messages = []
218
- results = parse_command_line_arguments(args)
219
- if not results['conf_file'].nil?
220
- Params['conf_file'] = File.expand_path(results['conf_file'])
221
- end
222
-
223
- #load yml params if path is provided and exists
224
- if Params['conf_file'].nil?
225
- @init_debug_messages << 'Configuration file was not provided.' + \
258
+ #load yml params if path is provided and exists
259
+ if Params['conf_file'].nil?
260
+ @init_debug_messages << 'Configuration file was not provided.' + \
226
261
  'Skipping loading file parameters.'
262
+ else
263
+ if File.exist?(Params['conf_file'])
264
+ @init_debug_messages << "Loading parameters from configuration file:'#{Params['conf_file']}'"
265
+ if not read_yml_params(File.open(Params['conf_file'], 'r'))
266
+ @init_debug_messages << "Bad configuration file #{Params['conf_file']}."
267
+ end
227
268
  else
228
- if File.exist?(Params['conf_file'])
229
- @init_debug_messages << "Loading parameters from configuration file:'#{Params['conf_file']}'"
230
- read_yml_params(File.open(Params['conf_file'], 'r'))
231
- else
232
- @init_debug_messages << "Configuration file path:'#{Params['conf_file']}' does not exist. " + \
269
+ @init_debug_messages << "Configuration file path:'#{Params['conf_file']}' does not exist. " + \
233
270
  "Skipping loading file parameters."
234
- end
235
- end
236
-
237
- #override command line argument
238
- results.keys.each do |result_name|
239
- override_param(result_name, results[result_name])
240
271
  end
272
+ end
241
273
 
242
- print_global_parameters
243
-
244
- # Prints help and parameters if needed.
245
- puts @help_messages unless @help_messages.empty?
246
- puts @init_debug_messages if Params['print_params_to_stdout']
247
- exit unless @help_messages.empty?
274
+ #override command line argument
275
+ results.keys.each do |result_name|
276
+ override_param(result_name, results[result_name])
248
277
  end
249
278
 
250
- # Load yml params and override default values.
251
- # raise exception if a loaded yml param does not exist. or if types mismatch occurs.
252
- def Params.read_yml_params(yml_input_io)
253
- proj_params = YAML::load(yml_input_io)
254
- proj_params.keys.each do |param_name|
255
- override_param(param_name, proj_params[param_name])
279
+ print_global_parameters
280
+
281
+ # Prints help and parameters if needed.
282
+ if @show_help_and_exit
283
+ # Print parameters + description and exit.
284
+ puts "Full list of parameters:"
285
+ Params.each do |name, param|
286
+ puts "--#{name}, #{param.type}, default:#{param.value}\n\t#{param.desc}"
256
287
  end
288
+ exit
257
289
  end
258
-
259
- # Parse command line arguments
260
- def Params.parse_command_line_arguments(args)
261
- results = Hash.new # Hash to store parsing results.
262
- options = Hash.new # Hash of parsing options from Params.
263
-
264
- # Define options switch for parsing
265
- # Define List of options see example on
266
- # http://ruby.about.com/od/advancedruby/a/optionparser2.htm
267
- opts = OptionParser.new do |opts|
268
- @globals_db.values.each do |param|
269
- tmp_name_long = "--" + param.name + "=MANDATORY" # Define a command with single mandatory parameter
270
- tmp_value = "Default value:" + param.value.to_s # Description and Default value
271
-
272
- # Define type of the mandatory value
273
- # It can be integer, float or String(for all other types).
274
- case( param.type )
275
- when 'Integer' then value_type = Integer
276
- when 'Float' then value_type = Float
277
- else value_type = String
278
- end
279
- # Switches definition - according to what
280
- # was pre-defined in the Params
281
- opts.on(tmp_name_long, value_type, tmp_value) do |result|
282
- if result.to_s.upcase.eql? 'TRUE'
283
- results[param.name] = true
284
- elsif result.to_s.upcase.eql? 'FALSE'
285
- results[param.name] = false
286
- else
287
- results[param.name] = result
288
- end
289
- end
290
+ puts @init_debug_messages if Params['print_params_to_stdout']
291
+ end
292
+
293
+ # Load yml params and override default values.
294
+ # raise exception if a loaded yml param does not exist. or if types mismatch occurs.
295
+ def Params.read_yml_params(yml_input_io)
296
+ proj_params = YAML::load(yml_input_io)
297
+ return false unless proj_params.is_a?(Hash)
298
+ proj_params.keys.each do |param_name|
299
+ override_param(param_name, proj_params[param_name])
300
+ end
301
+ true
302
+ end
303
+
304
+ # Parse command line arguments
305
+ def Params.parse_command_line_arguments(args)
306
+ results = Hash.new # Hash to store parsing results.
307
+ options = Hash.new # Hash of parsing options from Params.
308
+
309
+ # Define options switch for parsing
310
+ # Define List of options see example on
311
+ # http://ruby.about.com/od/advancedruby/a/optionparser2.htm
312
+ opts = OptionParser.new do |opts|
313
+ @globals_db.values.each do |param|
314
+ tmp_name_long = "--#{param.name} #{param.name.upcase}" # Define a command with single mandatory parameter
315
+ tmp_value = param.desc + " Default value:" + param.value.to_s # Description and Default value
316
+
317
+ # Define type of the mandatory value
318
+ # It can be integer, float or String(for all other types).
319
+ case(param.type)
320
+ when 'Integer' then value_type = Integer
321
+ when 'Float' then value_type = Float
322
+ else value_type = String
290
323
  end
291
-
292
- # Define help command for available options
293
- # executing --help will printout all pre-defined switch options
294
- opts.on_tail("-h", "--help", "Show this message") do
295
- @help_messages << opts
324
+ # Switches definition - according to what
325
+ # was pre-defined in the Params
326
+ opts.on(tmp_name_long, value_type, tmp_value) do |result|
327
+ if result.to_s.upcase.eql? 'TRUE'
328
+ results[param.name] = true
329
+ elsif result.to_s.upcase.eql? 'FALSE'
330
+ results[param.name] = false
331
+ else
332
+ results[param.name] = result
333
+ end
296
334
  end
297
-
298
- opts.parse(args) # Parse command line
299
335
  end
300
- return results
301
- end # end of Parse function
302
-
303
- def Params.print_global_parameters
304
- @init_debug_messages << "\n"
305
- @init_debug_messages << 'Initialized global parameters:'
306
- @init_debug_messages << '---------------------------------'
307
- counter=0
308
- @globals_db.values.each do |param|
309
- counter += 1
310
- @init_debug_messages << "#{counter}: #{param.name}=#{param.value}"
336
+
337
+ # Define introduction text for help command
338
+ opts.banner =
339
+ "Usage: content_serve [options] or \n" +
340
+ " : backup_server [options] \n\n" +
341
+ "Description: This application for backuping files and folders\n" +
342
+ "There is two application: \n" +
343
+ "backup_server is server run on machine where files is backuped,\n" +
344
+ "content_server is application that run on machine from where files is copied.\n\n" +
345
+ "Before run applications:" +
346
+ "Before running backup_server and content server you need to prepare two configuration files\n" +
347
+ "Create configuration file for content server which should be located at ~/.bbfs/etc/file_monitoring.yml\n" +
348
+ "the content of the file is:
349
+ ------- begin of file_monitoring.yml --------
350
+ paths:
351
+ - path: ~/.bbfs/test_files # <=== replace with your local dir.
352
+ scan_period: 1
353
+ stable_state: 5
354
+ ------- end of file_monitoring.yml --------\n" +
355
+ "Create configuration file for backup server which should be located at \n" +
356
+ "~/.bbfs/etc/backup_file_monitoring.yml\n" +
357
+ "File content:
358
+ ------- begin of backup_file_monitoring.yml --------
359
+ paths:
360
+ - path: ~/.bbfs/backup_data # <=== replace with your local dir.
361
+ scan_period: 1
362
+ stable_state: 5
363
+ ------- end of backup_file_monitoring.yml --------\n\n" +
364
+ "Explanation about file_monitoring.yml and backup_file_monitoring.yml configuration files:
365
+
366
+ \"path:\" - say to program which folder to scan recursively in order to find new/changed files and folders.
367
+ \"scan_period:\" - how much time in seconds passed before two consecutive scans for files and directories.
368
+ \"stable_state:\" - how many scan_period passed until the file is considered stable.\n\n" +
369
+ "List of options:"
370
+
371
+
372
+ # Define help command for available options
373
+ # executing --help will printout all pre-defined switch options
374
+ opts.on_tail("-h", "--help", "Show this message") do
375
+ @show_help_and_exit = true
311
376
  end
312
- @init_debug_messages << '---------------------------------'
313
- end
314
377
 
315
- #Auxiliary method to retrieve the executable name
316
- def Params.executable_name
317
- /([a-zA-Z0-9\-_\.]+):\d+/ =~ caller[caller.size-1]
318
- return $1
378
+ opts.parse(args) # Parse command line
319
379
  end
320
- #define default params:
321
- # 1. configuration file
322
- Params.string('conf_file', nil, 'Configuration file path.')
323
- # 2. Print params to stdout
324
- Params.boolean('print_params_to_stdout', false, 'print_params_to_stdout or not during Params.init')
325
-
326
- private_class_method :print_global_parameters, :parse_command_line_arguments, \
327
- :raise_error_if_param_exists, :raise_error_if_param_does_not_exist, \
328
- :read_yml_params, :override_param, :executable_name
380
+ return results
381
+ end # end of Parse function
382
+
383
+ def Params.print_global_parameters
384
+ @init_debug_messages << "\n"
385
+ @init_debug_messages << 'Initialized global parameters:'
386
+ @init_debug_messages << '---------------------------------'
387
+ counter=0
388
+ @globals_db.values.each do |param|
389
+ counter += 1
390
+ @init_debug_messages << "#{counter}: #{param.name}=#{param.value}"
329
391
  end
392
+ @init_debug_messages << '---------------------------------'
393
+ end
394
+
395
+ def Params.to_simple_hash
396
+ @globals_db.map { |param|
397
+ param.value
398
+ }
399
+ end
400
+
401
+ #Auxiliary method to retrieve the executable name
402
+ def Params.executable_name
403
+ /([a-zA-Z0-9\-_\.]+):\d+/ =~ caller[caller.size-1]
404
+ return $1
405
+ end
406
+ #define default params:
407
+ # 1. configuration file
408
+ Params.string('conf_file', nil, 'Configuration file path.')
409
+ # 2. Print params to stdout
410
+ Params.boolean('print_params_to_stdout', false, 'print_params_to_stdout or not during Params.init')
411
+
412
+ private_class_method :print_global_parameters, :parse_command_line_arguments, \
413
+ :raise_error_if_param_exists, :raise_error_if_param_does_not_exist, \
414
+ :read_yml_params, :override_param, :executable_name
330
415
  end
331
416