lewt 0.5.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +22 -0
  3. data/README.md +238 -0
  4. data/bin/lewt +10 -0
  5. data/lib/config/customers.yml +33 -0
  6. data/lib/config/enterprise.yml +54 -0
  7. data/lib/config/settings.yml +10 -0
  8. data/lib/config/templates/invoice.html.liquid +63 -0
  9. data/lib/config/templates/invoice.text.liquid +40 -0
  10. data/lib/config/templates/meta.html.liquid +0 -0
  11. data/lib/config/templates/meta.text.liquid +1 -0
  12. data/lib/config/templates/metastat.html.liquid +2 -0
  13. data/lib/config/templates/metastat.text.liquid +8 -0
  14. data/lib/config/templates/report.html.liquid +29 -0
  15. data/lib/config/templates/report.text.liquid +15 -0
  16. data/lib/config/templates/style.css +461 -0
  17. data/lib/extension.rb +158 -0
  18. data/lib/extensions/calendar-timekeeping/apple_extractor.rb +63 -0
  19. data/lib/extensions/calendar-timekeeping/calendar-timekeeping.rb +65 -0
  20. data/lib/extensions/calendar-timekeeping/extractor.rb +62 -0
  21. data/lib/extensions/calendar-timekeeping/gcal_extractor.rb +61 -0
  22. data/lib/extensions/calendar-timekeeping/ical_extractor.rb +52 -0
  23. data/lib/extensions/liquid-renderer.rb +106 -0
  24. data/lib/extensions/metastat/metamath.rb +108 -0
  25. data/lib/extensions/metastat/metastat.rb +161 -0
  26. data/lib/extensions/simple-expenses.rb +112 -0
  27. data/lib/extensions/simple-invoices.rb +93 -0
  28. data/lib/extensions/simple-milestones.rb +102 -0
  29. data/lib/extensions/simple-reports.rb +81 -0
  30. data/lib/extensions/store.rb +81 -0
  31. data/lib/lewt.rb +233 -0
  32. data/lib/lewt_book.rb +29 -0
  33. data/lib/lewt_ledger.rb +149 -0
  34. data/lib/lewtopts.rb +170 -0
  35. data/tests/LEWT Schedule.ics +614 -0
  36. data/tests/expenses.csv +1 -0
  37. data/tests/milestones.csv +1 -0
  38. data/tests/run_tests.rb +14 -0
  39. data/tests/tc_Billing.rb +29 -0
  40. data/tests/tc_CalExt.rb +44 -0
  41. data/tests/tc_Lewt.rb +37 -0
  42. data/tests/tc_LewtExtension.rb +31 -0
  43. data/tests/tc_LewtLedger.rb +38 -0
  44. data/tests/tc_LewtOpts.rb +26 -0
  45. metadata +158 -0
data/lib/lewt.rb ADDED
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'date'
4
+ require 'yaml'
5
+ require 'optparse'
6
+ require_relative 'lewtopts.rb'
7
+ require_relative 'extension.rb'
8
+ require_relative 'lewt_book.rb'
9
+ require_relative 'lewt_ledger.rb'
10
+
11
+
12
+ # Author:: Jason Wijegooneratne (mailto:code@jwije.com)
13
+ # Copyright:: Copyright (c) 2014 Jason Wijegooneratne
14
+ # License:: MIT. See LICENSE.md distributed with the source code for more information.
15
+
16
+ # This module acts as a container for the LEWT namespace
17
+ module LEWT
18
+
19
+ VERSION = "0.5.12"
20
+
21
+ # The Lewt class contains the major functionality of this program.
22
+ # It handles loading all extensions, gathering the results and passing options ariound the place.
23
+ # It also works quite closely with the LewtExtension and LewtOpts classes.
24
+ class Lewt
25
+
26
+ # Can be used to split strings passed to lewt through CL optios ie:
27
+ # "acme,wayne_corp".split(CLIENT_SPLIT_REGEX) # get each argument for client mathching
28
+ OPTION_DELIMITER_REGEX = /[,+:]/
29
+
30
+ # This matches symbols passed thought command ie: -p meta-stat => meta_stat
31
+ OPTION_SYMBOL_REGEX = /\W/
32
+
33
+ def initialize( library_options = nil )
34
+ core_settings = YAML.load_file( File.expand_path( '../config/settings.yml', __FILE__) )
35
+ if File.exists? File.expand_path( '~/.lewt_settings', __FILE__)
36
+ core_settings.merge! YAML.load_file( File.expand_path( '~/.lewt_settings', __FILE__) )
37
+ end
38
+
39
+ @lewt_stash = core_settings['lewt_stash'] || File.expand_path('../', __FILE__) + "/config/"
40
+ @settings = YAML.load_file( @lewt_stash + 'settings.yml' )
41
+
42
+ # Start by loading the local config files
43
+ @customers = YAML.load_file(@lewt_stash + "customers.yml")
44
+ @enterprise = YAML.load_file(@lewt_stash + "enterprise.yml")
45
+
46
+ # Referenceall registered extension for later invocation
47
+ @extensions = LEWT::Extension.new.lewt_extensions
48
+
49
+
50
+ # Load core extensions
51
+ load_extensions( File.expand_path('../extensions', __FILE__) )
52
+
53
+ if core_settings.has_key?("lewt_stash")
54
+ # load user defined extesnions
55
+ load_extensions
56
+ end
57
+
58
+ # Stores default options returned from extensions
59
+ # and the LEWT defaults at large
60
+ options = {}
61
+ @command = ARGV[0]
62
+
63
+ # argument supplied for `cmd' (if any). ignore option flags IE args that start with the `-' symbol
64
+ @argument = ARGV[1] == nil || ARGV[1].match(/\-/i) ? nil : ARGV[1]
65
+
66
+ @options = LewtOpts.new( @extensions, library_options )
67
+
68
+ parse_internal_commands
69
+ end
70
+
71
+ # Runs extract, process, render hooks.
72
+ def run
73
+ extract = fire_hooks("extract", @options)
74
+ process = fire_hooks("process", @options, extract )
75
+ render = fire_hooks("render", @options, process )
76
+ end
77
+
78
+
79
+ # fn returns the desired customer given there name or alias.
80
+ # A REGEXP query can be passed to this object i.e. "ACME|NovaCorp|..."
81
+ # to match multiple customers.
82
+ # query [String]:: The query to search against.
83
+ def get_client( query )
84
+ client = nil
85
+ @customers.each do |c|
86
+ buildQ = [ c["name"], c["alias"] ].join("|")
87
+ regex = Regexp.new(buildQ, Regexp::IGNORECASE)
88
+ if regex.match( query ) != nil
89
+ client = c
90
+ end
91
+ end
92
+ return client
93
+ end
94
+
95
+
96
+ # Fire the logic loop from the specified hook onwards. Used when piping data in from CL
97
+ # hook [Sting]:: extract, process, or render
98
+ # data:: The data to pass to fire_hooks
99
+ def hook_process (hook, data)
100
+ case hook
101
+ when "extract"
102
+ extracted_data = fire_hooks("extract",@options,data)
103
+ hook_process("process", extracted_data)
104
+ when "process"
105
+ processed_data = fire_hooks("process",@options,data)
106
+ hook_process("render",processed_data)
107
+ when "render"
108
+ render_data = fire_hooks("render",@options,data)
109
+ else
110
+ raise ArugmentError, "#{self.class.name}.hook_process requires the start hook to be either render or process"
111
+ end
112
+ end
113
+
114
+ # Fire a hook with the given options and overloaded parameters.
115
+ # hook [String]:: Expected hooks are 'extract', 'process', 'render'.
116
+ # options [Hash]:: The options gathered from using LewtOpts
117
+ # data [Mixed]:: The data to pass to the extensions.
118
+ def fire_hooks( hook, options, *data )
119
+ algamation = Array.new
120
+ @extensions.each { |e|
121
+ ## filter hooks
122
+ filter_regex = /#{options[hook.to_sym].gsub(",","|")}/
123
+ if e.methods.include?(hook.to_sym) and e.command_name.match(filter_regex)
124
+ case hook
125
+ when "extract"
126
+ algamation.concat e.extract(options)
127
+ when "process"
128
+ processed = e.process(options, *data)
129
+ if processed.kind_of? Array
130
+ algamation.concat processed
131
+ else
132
+ algamation.push processed
133
+ end
134
+ when "render"
135
+ algamation.concat e.render(options, *data)
136
+ # dump render output to console of option specified.
137
+ puts algamation if options[:dump_output] == true
138
+ end
139
+ end
140
+ }
141
+ return algamation;
142
+ end
143
+
144
+
145
+ protected
146
+
147
+ # reads input from standard INPUT
148
+ def read_stdin
149
+ data = ""
150
+ while line = $stdin.gets
151
+ data += line
152
+ end
153
+ return data
154
+ end
155
+
156
+ # Parses lewsts intenral commands. If none have been invoked it simple returns.
157
+ def parse_internal_commands
158
+ return if @command == nil
159
+ # raise argument error if command invoked without argument
160
+ if @argument == nil and @command != nil
161
+ puts @command
162
+ raise ArgumentError, "Class #{self.class.name} requires an argument t be supplied with a command"
163
+ end
164
+
165
+ if @command.match(/pipe/)
166
+ # pipe stdin into fire_hook(@argument) event
167
+ data = Psych.load(read_stdin)
168
+ if data != nil
169
+ hook_process(@argument, data)
170
+ else
171
+ raise ArgumentError, "could not parse STDIN pipe as YAML data."
172
+ end
173
+ exit
174
+ end
175
+
176
+ end
177
+
178
+ # Loads all installed LEWT extensions by checking the ext_dir setting variable for available ruby files.
179
+ # directory [String]:: The path where to look for extensions as a string.
180
+ def load_extensions( directory = @lewt_stash + "extensions" )
181
+ raise Exception, "Directory does not exist: #{directory}" if !Dir.exists?(directory)
182
+
183
+ Dir.foreach( directory ) do |file|
184
+ next if (file =~ /\./) == 0
185
+ # Cannot match with File.directory?(file) due to how ruby performs
186
+ # this test internaly when script is called from another dir.
187
+ # Therefor some REGEX will be used to match the .rb file extension instead...
188
+ if file.match(/\.rb/) != nil
189
+ load(directory + "/" + file)
190
+ ext_object = initialize_extension( file )
191
+ else
192
+ # is a directory
193
+ # load file in dir named {dir_name}.rb
194
+ load "#{directory}/#{file}/#{file}.rb"
195
+ ext_object = initialize_extension(file)
196
+ end
197
+ end
198
+
199
+ # load extensions packaged as GEMS
200
+ if @settings['gem_loads'] != nil
201
+ @settings['gem_loads'].split(Lewt::OPTION_DELIMITER_REGEX).each do |g|
202
+ match = g.split("/")
203
+ ext_object = initialize_gem(match[0], match[1])
204
+ end
205
+ end
206
+
207
+ end
208
+
209
+ # This method initialised a gem as specifed in your settings file.
210
+ # gem_require [String]:: The gem require path as a string
211
+ # gem_class [String]:: The gem class name for initialisation
212
+ def initialize_gem( gem_require, gem_class )
213
+ require gem_require
214
+ extension = eval( gem_class + ".new")
215
+ return @extensions.last
216
+ end
217
+
218
+ # fn basically anticipates a class name given its file path and then call its registerHanders method.
219
+ # Class names are transformed into UC words. '-' are interpreted as spaces in this conversion, and are
220
+ # striped afterwards to return something like 'invoice-renderer.rb' >>> 'InvoiceRenderer' ready for
221
+ # evaluation.
222
+ # file [String]:: The file name as a string
223
+ def initialize_extension ( file )
224
+ classConvention = file.gsub("-", " ").split.map(&:capitalize).join(' ').gsub(" ","").gsub(".rb","")
225
+ extInit = ("LEWT::" + classConvention + ".new").to_s
226
+ extension = eval( extInit )
227
+ # extension will be registered on init so just reference the last one
228
+ return @extensions.last
229
+ end
230
+
231
+ end
232
+
233
+ end
data/lib/lewt_book.rb ADDED
@@ -0,0 +1,29 @@
1
+ # Author:: Jason Wijegooneratne (mailto:code@jwije.com)
2
+ # Copyright:: Copyright (c) 2014 Jason Wijegooneratne
3
+ # License:: MIT. See LICENSE.md distributed with the source code for more information.
4
+
5
+ module LEWT
6
+
7
+
8
+ # The LEWTBook is used by extractors as a generic data structure to adhere to when
9
+ # returning there results.
10
+ # It follows a basic *general ledger* format without the double-entry book keeping.
11
+ #
12
+ # ===Usage:
13
+ #
14
+ # lewtbook = LEWTBook.new()
15
+ # lewtbook.add_row( LEWTLedger.new( params, ... ) )
16
+ #
17
+ class LEWTBook < Array
18
+ # adds a row to this element as per array.push. only accespts LEWTLedger objects as entries.
19
+ # element [LEWTLedger]:: An initialised LEWTLedger object containing your data.
20
+ def push ( element )
21
+ if element.kind_of?(LEWT::LEWTLedger)
22
+ self.class.superclass.instance_method(:push).bind(self).call element
23
+ else
24
+ raise TypeError, "Class #{self.class.name} only accepts LEWT::LEWTLedger objects as its contents"
25
+ end
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,149 @@
1
+
2
+
3
+ module LEWT
4
+
5
+ # LEWTLedger is a pre-formated hash structure that conforms somewhat to a standard general ledger entry.
6
+ #
7
+ # ===Keys
8
+ # date_start:: Start date the entry occured on
9
+ # date_end:: End date the entry occured on
10
+ # category:: Some sort of general category for this entry i.e: 'Hourly Income', 'Operating Expenses' etc.
11
+ # entity:: The entiry with whom this transaction occured with
12
+ # description:: A description of the entry
13
+ # quantity:: How many units
14
+ # unit_cost:: The cost per unit
15
+ # sub_total (optional):: A total or defaults to quantity * unit_cost
16
+ # gst (optional):: The GST (VAT) amount to be added for this entry. Defaults to 0.
17
+ # total (optional):: The total, including tax, for this entry. Defaults to sub_total + gst
18
+ #
19
+ # ===Usage
20
+ # ledger = LEWTLedger.new(params, ...)
21
+ #
22
+ # Furthermore LEWTLedger provides some methods to work with metatags. Metatags can be embedded inside your extraction sources.
23
+ # I like to put mine in my 'description' fields, it works well with Calender Extractor. The meta data is basically a hash tag, you
24
+ # can do stuff like this:
25
+ #
26
+ # '#happiness=10/10'
27
+ # '#ignore-cost'
28
+ #
29
+ # meta tags that do not assign a value [ie: =something] will evaluate to a boolean true flag. If you assign a value it must
30
+ # be a fraction, this will be evaluated as a ruby Rational type. Your extensions can respond to these tags however they like.
31
+ # The metatags can be accessed with the <tt>metatags</tt> reader attribute:
32
+ # ledger_data.metatags
33
+ #
34
+
35
+ class LEWTLedger < Hash
36
+
37
+ attr_reader :metatags
38
+
39
+ # This is a general matching regex for metatags.
40
+ MATCH_SINGLE_META_REGEX = /[#](\S*)/
41
+ MATCH_MULTIPLE_META_REGEX = /#\S*/
42
+
43
+ def initialize (args)
44
+ raise ArgumentError, "#{self.class.name} was not instantized with valid parameters" if valid?(args) == false
45
+ self[:date_start] = args[:date_start]
46
+ self[:date_end] = args[:date_end]
47
+ self[:category] = args[:category]
48
+ self[:entity] = args[:entity]
49
+ self[:description] = args[:description]
50
+ self[:quantity] = args[:quantity]
51
+ self[:unit_cost] = args[:unit_cost]
52
+ self[:sub_total] = self[:sub_total] || self[:quantity] * self[:unit_cost]
53
+ self[:gst] = args[:gst] || 0
54
+ self[:total] = args[:total] || ( self[:sub_total] + self[:gst] )
55
+ @metatags = parse_meta_tags(:description)
56
+ strip_readable_meta if @metatags != nil
57
+ end
58
+
59
+ # parses a field on this object for meta data. Meta data can be embedded inside the ledger fields
60
+ # as a string by prefixing it with the '#' symbol. If you assign a value to the meta field with the '='
61
+ # symbol, its value will be interpreted as a number.
62
+ # ie:
63
+ # #good-pay // true
64
+ # #happiness=6/10 // Rational(6,10)
65
+ # field_key [Symbol]:: the ledger key you wish to parse as a symbol.
66
+ def parse_meta_tags ( field_key )
67
+ value = self[field_key]
68
+ tags = parse_tags value
69
+ return tags
70
+ end
71
+
72
+ protected
73
+
74
+ # strips the meta data from a field so that it is no longer readable. leaves the metatags property on the object intact however
75
+ # field:: A Symbol corresponding to the field on this object to strip. Defaults to the description field.
76
+ def strip_readable_meta ( field = :description )
77
+ self[field].scan(LEWTLedger::MATCH_MULTIPLE_META_REGEX).each do |m|
78
+ self[field].slice!(m).strip!
79
+ end
80
+ end
81
+
82
+ # this function extracts all tags/values from a given string.
83
+ # string [String]:: a string to search for meta tags in.
84
+ def parse_tags (string)
85
+ tags = nil
86
+ string.scan(LEWTLedger::MATCH_SINGLE_META_REGEX) { |t|
87
+ if tags == nil
88
+ tags = Hash.new
89
+ end
90
+ tag_value = parse_tag_value t[0]
91
+ tag_name = parse_tag_name t[0]
92
+ tags[tag_name.gsub(/\W/,"_").to_sym] = tag_value
93
+ }
94
+ return tags
95
+ end
96
+
97
+ # parses the name of a tag and returns it as a symbol to be used as a hash key
98
+ # tag [string] a string containing the a singular meta tag.
99
+ def parse_tag_name( tag )
100
+ match_name = /[^=]*/
101
+ m = tag.match(match_name)
102
+ return m[0]
103
+ end
104
+
105
+ # parses the value of a meta tag string. if just the string is given (ie: no = xx/xx) then the tag will have
106
+ # a value of true returned for it.
107
+ # tag [String]:: a meta tag string
108
+ def parse_tag_value ( tag )
109
+ match_value = /[=]\d*\/\d*/
110
+ match = tag.match match_value
111
+ # if no value found then this must be a boolean switch (because a tag was parsed from the field!) so set value to true
112
+ value = match != nil ? extract_fraction(match[0]) : true
113
+ return value
114
+ end
115
+
116
+ # extracts a mathematical expression from a single tag
117
+ # format: Num +-/* Num
118
+ # string:: the string to extract the fraction from
119
+ def extract_fraction ( string )
120
+ match_fraction = /(\d{1,})([\/\+])(\d{1,})+/
121
+ # m = string.match(match_fraction)[0]
122
+ m = string.match(match_fraction)
123
+ value = nil
124
+ if m != nil
125
+ value = Rational m[0]
126
+ end
127
+ return value
128
+ end
129
+
130
+ # validates the arguments this object is initialised with.
131
+ # args [Hash]:: The argument hash passed to this class on initialize
132
+ def valid?(args)
133
+ raise TypeError, "#{self.class.name} must be initialised with a hash" if not args.kind_of?(Hash)
134
+ args.each { |k,v|
135
+ case k
136
+ when :date_start, :date_end
137
+ raise TypeError, "Expected Time type" unless v.kind_of? Time
138
+ when :category, :entity, :description
139
+ raise TypeError, "Expected a string" unless v.kind_of? String
140
+ when :quantity, :unit_cost, :sub_total, :gst, :total
141
+ raise TypeError, "Expected a number" unless v.kind_of? Numeric
142
+ end
143
+ }
144
+ return true
145
+ end
146
+
147
+ end
148
+
149
+ end
data/lib/lewtopts.rb ADDED
@@ -0,0 +1,170 @@
1
+ # Author:: Jason Wijegooneratne (mailto:code@jwije.com)
2
+ # Copyright:: Copyright (c) 2014 Jason Wijegooneratne
3
+ # License:: MIT. See LICENSE.md distributed with the source code for more information.
4
+
5
+
6
+ module LEWT
7
+
8
+ # This is the options handling class for LEWT extensions. It handles translating extension options for usage in the command line
9
+ # & library run-times and acts as a sort of wrapper class for this functionality.
10
+ #
11
+ # ===LEWT's reserved option flags
12
+ #
13
+ # -x --extract:: what extractor[s] to use
14
+ # -p --process:: what processor[s] to use
15
+ # -o --render:: what renderer[s] to use
16
+ # -t --target:: target
17
+ # -s --start:: start target date
18
+ # -e --end:: end target date
19
+ #
20
+ # The user defined values for these options are readable by extensions at runtime.
21
+
22
+
23
+ class LewtOpts < Hash
24
+
25
+ attr_reader :options, :defaults
26
+
27
+ # Sets up this extension.
28
+ def initialize ( extensions, library_options = nil )
29
+ default_options = {
30
+ :start => {
31
+ :definition => "Start time for LEWT snapshot",
32
+ :default => DateTime.now - 8,
33
+ :type => DateTime,
34
+ :short_flag => "-s"
35
+ },
36
+ :end => {
37
+ :definition => "End time for LEWT snapshot",
38
+ :default => DateTime.now,
39
+ :type => DateTime,
40
+ :short_flag => "-e"
41
+ },
42
+ :target => {
43
+ :definition => "The target to filter data with. In the case of most extensions this will be the target customers but other alternatives are possible",
44
+ :short_flag => "-t",
45
+ :type => String
46
+ },
47
+ :extract => {
48
+ :definition => "The extraction extension(s) LEWT should use to pull data with. This can be a comma separated list for multiple sources",
49
+ :default => "calendar",
50
+ :type => String,
51
+ :short_flag => "-x"
52
+ },
53
+ :process => {
54
+ :definition => "The processor extensions LEWT should use to process the data with.",
55
+ :default => "invoice",
56
+ :type => String,
57
+ :short_flag => "-p"
58
+ },
59
+ :render => {
60
+ :definition => "The render(s) LEWT should use to output the data with. This can be a comma separate list for multiple outputs.",
61
+ :default => "liquid_render",
62
+ :type => String,
63
+ :short_flag => "-o"
64
+ },
65
+ :dump_output => {
66
+ :definition => "Toggle dumping output to console or log",
67
+ :default => true,
68
+ :short_flag => "-d"
69
+ }
70
+ }
71
+
72
+ # gather extension options & merge into LEWTs defaults
73
+ extensions.each do |e|
74
+ if e.options != nil
75
+ default_options.merge!( e.options )
76
+ end
77
+ end
78
+
79
+ @defaults = default_options
80
+
81
+ # determine if using LEWT from command line (CL) or as a drop in library and parse options accordingly
82
+ if File.basename($0).match(/\.rb/) != nil
83
+ parse_library_options( default_options, library_options )
84
+ else
85
+ parse_command_line_options( default_options )
86
+ end
87
+
88
+ end
89
+
90
+ # handles parsing & translating options in command line mode
91
+ # sets the value of the instantized object equal to the parsed options hash
92
+ # default_options [Hash]:: The default options gathered from all extension & Lewt itself to use in case user supplied values aren't given.
93
+ def parse_command_line_options( default_options )
94
+ options = self
95
+
96
+ # Parse internal commands before extension commands & options to avoid any conflicts & to avoid extension invocation
97
+ # in case a internal command is called.
98
+ OptionParser.new do |opts|
99
+
100
+ default_options.each do | name, details |
101
+ # translate options default value if defined
102
+ if details.key?(:default) == true
103
+ options[name] = details[:default]
104
+ end
105
+
106
+ cl_type = details[:type].to_s == "DateTime" ? String : details[:type]
107
+ cl_sub = details[:type].to_s == "DateTime" ? "Date" : details[:type]
108
+
109
+ cl_option = "--#{name.to_s.gsub("_","-")} [#{cl_sub}]"
110
+
111
+ if details.key?(:short_flag) == true && details.key?(:type) == true
112
+ opts.on( details[:short_flag], cl_option, cl_type, details[:definition] ) do |o|
113
+ options[ name ] = prepare_input( details, o )
114
+ end
115
+ elsif details.key?(:short_flag) == true && details.key?(:type) == false
116
+ opts.on( details[:short_flag], "--#{name.to_s.gsub("_","-")}", details[:definition] ) do |o|
117
+ options[ name ] = prepare_input( details, o )
118
+ end
119
+ elsif details.key?(:short_flag) == false
120
+ opts.on( cl_option, cl_type, details[:definition] ) do |o|
121
+ options[ name ] = prepare_input( details, o )
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+ opts.banner = "Usage: lewt -x EXTRACTOR -p PROCESSOR -o RENDERER"
128
+ opts.version = LEWT::VERSION
129
+
130
+ end.parse!(ARGV)
131
+
132
+ return options
133
+ end
134
+
135
+ # handles parsing & translating options in library mode
136
+ # sets the value of the instantized object equal to the parsed options hash
137
+ # default_options [Hash]:: The default options gathered from all extension & Lewt itself to use in case user supplied values aren't given.
138
+ # library_options [Hash]:: Some options translated for use in lib mode
139
+ def parse_library_options ( default_options, library_options )
140
+ options = Hash.new
141
+
142
+ default_options.each do | name, details |
143
+ # translate options default value if defined
144
+ if details.key?(:default) == true
145
+ options[name] = details[:default]
146
+ end
147
+ end
148
+
149
+ # merge library options with options array
150
+ options.merge!(library_options)
151
+
152
+ # assign options to self
153
+ options.each do |k,v|
154
+ self[k] = v
155
+ end
156
+ end
157
+
158
+ # this function basically exists to get around the limited variable initialization functionality of
159
+ # Ruby standard option parser class.
160
+ def prepare_input ( details, value )
161
+ type = details[:type]
162
+ if type == DateTime
163
+ initialized_value = DateTime.parse(value)
164
+ else
165
+ initialized_value = value
166
+ end
167
+ return initialized_value
168
+ end
169
+ end
170
+ end