option_list 1.1.0 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- OWQxY2I0ZTM2NjM1OTBiZDU2MWNmZDk4MjcyMDQ1ZGUzYWQzNDcyMA==
5
- data.tar.gz: !binary |-
6
- NDUyZWQxNmQ5MzMwZTkzZThhZTFjNzhjMTNmN2Y4ZmY1NDU2N2RmNQ==
2
+ SHA256:
3
+ metadata.gz: 3fc80941391b0ec0003d6410fbacab0e5f54726d7ead3e0a30b85b2a1302f865
4
+ data.tar.gz: 8c13ce0b7069b663805c86f267996794d4a53261c2cf7cce9922284eed3dadaf
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ZGNhMjA2NjExMzNjNDAzNzdjNmZmODJkODg1NmQwZDYzOTg2MTkxNTFiMDUx
10
- MmU1NGFkMTMzZGE1MjI1MzU3MWE2M2U3MzEwMDEwYWYyNDI0YmIzYjk4MGQx
11
- NDM3NjEwNTEwYzkxY2YxNjY5MWJmZjc0NDY3NmU3MmMyZmE4NGU=
12
- data.tar.gz: !binary |-
13
- ZDViOTVkN2U5NjMyZDNlYjliZDdlODk2NTM2MzFiZTJmMDExOThjNzhhOTMw
14
- MTM1Yjk5ZTEwNjBiYTE2NmQzNzRkYWI4OWIyM2JhNGIwMGY2NzRiNGE2Zjli
15
- MGJmMjMyYjliNDAzNmVmYmY2MGM1MzBmMzg1ODE1NGEwMDgzZTM=
6
+ metadata.gz: 19e4ce85288187faa5326495572e6b33df72b30792c174e8922aabbcb9e10cd329f8f88e612a704a052f349bd066ae0196f3522b500ddde7bb7bb375000e1c9f
7
+ data.tar.gz: bac17c293cd014626a1e03f069f89315be0615aea23c3c2943846d3698c0cafda9bf138e8da37e7b555a234e029a80983f9bc52e70e2901ca4012f7171c7e48b
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.bat
2
+ *.zip
3
+ *.tmp
4
+ *.gem
5
+ *.rbc
6
+ .bundle
7
+ .config
8
+ .yardoc
9
+ Gemfile.lock
10
+ InstalledFiles
11
+ _yardoc
12
+ coverage
13
+ doc/
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ spec/reports
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at peter.c.camilleri@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in option_list.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # OptionList
2
+
3
+ This gem addresses the fact that parameter validation is long and
4
+ tedious and something needs to be done about that. This gem implements
5
+ the idea that parameters be described separately and validated in a
6
+ single line of client method code.
7
+
8
+ Most of what this gem does has been subsumed by the Ruby Language itself,
9
+ starting with version 1.9 and further with versions 2.0 and beyond.
10
+
11
+ Finally, I'd like to add a personal note about this code. This was my first
12
+ attempt at creating a gem. As such there is very much a newbie vibe to the
13
+ code. I hope you can chalk this up to just a part of the learning process.
14
+ None the less, if there are improvements that you (the reader) could suggest,
15
+ I'd really appreciate hearing about them.
16
+
17
+ Thanks in advance, Peter.
18
+
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ gem 'option_list'
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install option_list
33
+
34
+ The options_list gem is at: ( https://rubygems.org/gems/options_list )
35
+
36
+ ## Usage
37
+
38
+ The use of option_list occurs in three phases: Describing the Parameters,
39
+ Passing in Parameters and Validating/Accessing the Parameters. This can be
40
+ seen in the following example:
41
+ ```ruby
42
+ module ReadLine
43
+ #Create the parameter specification (simplified for brevity)
44
+ @spec = OptionList.new([:buffer, :history, :no_history], {:depth => 50}) do |options|
45
+ fail "Depth must be an integer" unless options.depth.is_a(Integer)
46
+ fail "Depth must be positive" if options.depth < 1
47
+ end
48
+
49
+ class << self
50
+ attr_reader :spec
51
+ end
52
+
53
+ def read_line(prompt, *options)
54
+ @options = ReadLine.spec.select(options)
55
+ #Further code deleted for brevity.
56
+ #Somewhere along the line it records the last line.
57
+ buffer_line(current_line)
58
+ current_line
59
+ end
60
+
61
+ def buffer_line(line)
62
+ @line_buffer << line if @options.history?
63
+ @line_buffer.delete_at(0) if @line_buffer.length > @options.depth
64
+ end
65
+ end
66
+ ```
67
+ The option_list gem is described in the The option_list User's Guide
68
+ which covers version 1.1.1 which has no material change from 1.1.3
69
+
70
+ ## Contributing
71
+
72
+ #### Plan A
73
+
74
+ 1. Fork it ( https://github.com/PeterCamilleri/option_list/fork )
75
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
76
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
77
+ 4. Push to the branch (`git push origin my-new-feature`)
78
+ 5. Create new Pull Request
79
+
80
+ #### Plan B
81
+
82
+ Go to the GitHub repository and raise an issue calling attention to some
83
+ aspect that could use some TLC or a suggestion or an idea.
84
+
85
+ ## License
86
+
87
+ The gem is available as open source under the terms of the
88
+ [MIT License](./LICENSE.txt).
89
+
90
+ ## Code of Conduct
91
+
92
+ Everyone interacting in the fully_freeze project’s codebases, issue trackers,
93
+ chat rooms and mailing lists is expected to follow the
94
+ [code of conduct](./CODE_OF_CONDUCT.md).
95
+
data/docs/OL_UG.odt ADDED
Binary file
data/docs/OL_UG.pdf ADDED
Binary file
Binary file
data/lib/option_list.rb CHANGED
@@ -4,158 +4,59 @@ require 'set'
4
4
  #This file contains the code for the \OptionList class that implements smart
5
5
  #and easy options for functions. It has the virtue of defining function
6
6
  #options clearly in a single place instead of spread out in complex code.
7
- #A classic but unclear sequence in many functions is the use of boolean values
8
- #to control or switch on or off some option. For example consider the well
9
- #known readline function:
10
- # cmd = readline(">", false)
11
- #See the boolean at the end? It says "false". What is "false"? Who knows? You
12
- #need to dig deeper or guess or just cut and paste without understanding. What
13
- #if, instead, the code looked like:
14
- # cmd = readline(">", :nohistory)
15
- #The boolean has been replaced by something a lot clearer. The problem with
16
- #such clarity is that it involves a lot more effort than the lazy boolean. The
17
- #\OptionList class aims to solve that issue by making useful, flexible options
18
- #just about as easy to use as the lazy way.
19
- #==== Warning: This code is most opinionated! ;-)
20
- #The philosophy and opinion expressed through this code is that errors should
21
- #be detected as close to the point of error as possible and that an error is
22
- #preferable to running with potentially incorrect results. As a result, it
23
- #will be noted that the programmer does not hesitate to use the fAE, a wrapper
24
- #of the "fail" keyword, liberally throughout the code to achieve this end.
25
- #Complimentary to this is the idea that the library (gem) writer should do as
26
- #much of the "heavy lifting" as possible, with clear, detailed documentation so
27
- #that the library (gem) user does not have to work hard or be lost or confused.
28
- #Only time will tell to what extent these lofty goals have been achieved.
29
- #Hopefully, with good feedback, this and other code libraries will improve.
30
- #=== Version 1.0.1
31
- #This version represents a major overhaul of the \OptionList class. In
32
- #particular, the selected option data and the dynamic methods used to access
33
- #that data are no longer contained in the option list object but instead in
34
- #a singleton subclass of Hash that is returned by the select method. There
35
- #are several advantages to this, but the main one is that since \OptionList
36
- #objects now only contain specification and default values, they are much more
37
- #thread safe than before. While there is nothing multi-threaded about the
38
- #\OptionList class itself, it is reasonable to assume that a function option
39
- #handler could very easily end up embedded in such an environment. In fact, my
40
- #first major test of the class ran into this exact issue.
7
+ #==== User's Guide
8
+ #Most of the documentation for this gem has been moved to
9
+ #{Option List User's Guide}[http://teuthida-technologies.com/guides/OL_UG_Version_1_1_1.pdf]
10
+ #====Version 1.1.1
11
+ #Embraced reek and git and created the user's guide to pair down rdoc mark up
12
+ #to be less obtrusive to the code.
41
13
  #=== Version 1.1.0
42
- #Added a default value of false to signify that no default exists for a
14
+ #Added a default value of false to signify that no default exists for a
43
15
  #mandatory parameter.
44
16
  #Modified processing of array specs to avoid side effects in the parameters.
45
17
  class OptionList
46
18
 
47
19
  #The option list code version.
48
20
  def self.version
49
- '1.1.0'
21
+ OptionList::VERSION
50
22
  end
51
-
23
+
52
24
  #The option list code version. This is a redirect to the class method.
53
25
  def version
54
- self.class.version
26
+ OptionList::VERSION
55
27
  end
56
28
 
57
- #Create an option list from an array of option specifications. These
58
- #specifications consist of a number of array specifications and hash
59
- #specifications. These are described below:
60
- #==== Array Specification
61
- #Array specifications are used in cases where an option category may be one
62
- #of a fixed number of distinct symbol values or optionally nil to represent
63
- #no selection.
64
- #In this form of specification, the first element of the array is the
65
- #category of the option, and the second and following entries are the
66
- #allowed values for that category. The second element has a special role. It
67
- #is the default value for the category. This value may be one of:
68
- #* A symbol - The default symbolic value for this option.
69
- #* nil - The default value is nil and this setting is optional.
70
- #* false - There is no default value and this setting is mandatory.
71
- #The symbols used in each category must be unique across
72
- #all of the categories in the option list.
73
- #==== Hash Specification
74
- #Hash specifications are used to specify options that do not have a fixed set
75
- #of possible values. In this form of specification, the hash key symbol is
76
- #the category and the hash value is the default value for the category. It
77
- #may be nil or any other type or value. Allowed values are not listed.
78
- #==== Example:
79
- # @opt_list = OptionList.new([:history, :history, :nohistory], {:page_len => 42})
29
+ #Create an option list from an array of option specifications.
80
30
  #==== Parameters:
81
- #* option_specs - The comma separated option specifications, made into an
31
+ #* option_specs - The comma separated option specifications, made into an
82
32
  # array by the splat operator.
83
33
  #* select_block - An optional block of code that is called when selections
84
34
  # have been made. This allows for custom validations to be applied at that
85
35
  # point. This block should accept one argument, a reference to the option
86
36
  # list value object that is calling it for validation.
87
- #==== Dynamic Methods:
88
- #As option specifications are added, new methods are created in the value
89
- #object to allow for easy access to the option information. If the above
90
- #example were processed, the following methods would be added to the value
91
- #returned by the select method:
92
- #* history - would return the value of the :history category.
93
- #* history? - would return true if the :history option where active.
94
- #* nohistory? - would return true if the :nohistory option were active.
95
- #* page_len - would return the value of the :page_len category.
96
37
  #==== Exceptions:
97
38
  #* ArgumentError for a number of invalid argument conditions.
98
39
  def initialize(*option_specs, &select_block)
99
- fAE "Missing option specifications." if option_specs.empty?
40
+ error "Missing option specifications." if option_specs.empty?
100
41
  @mandatory = Array.new
101
42
  @categories = Hash.new
102
43
  @default = Hash.new
103
-
44
+
104
45
  option_specs.each do |spec|
105
46
  if spec.is_a?(Hash)
106
47
  hash_spec(spec)
107
48
  elsif spec.is_a?(Array)
108
49
  array_spec(spec)
109
50
  else
110
- fAE "Found #{spec.class} instead of Hash or Array."
51
+ error "Found #{spec.class} instead of Hash or Array."
111
52
  end
112
53
  end
113
-
54
+
114
55
  @select_block = select_block
115
56
  end
116
57
 
117
58
  #From the possible options, select the actual, in force, options and return
118
- #an access object for use in the code. These options may take several forms:
119
- #=== Types of option data:
120
- #* A symbol - For categories with a specified symbol list, simply list one
121
- # of the allowed symbols.
122
- #* A hash - For any type of category, a hash may be used in the the form
123
- # {category => value}. Note that for categories with a specified symbol list
124
- # the value must be a symbol in the list.
125
- #* Mixed - Symbols and hashes can be mixed in an array (see below on how this
126
- # is done) Note: Option order does not matter.
127
- #Some examples:
128
- # o = foo(:sedan, :turbo)
129
- # o = foo({:style=>:sedan})
130
- # o = foo(page_len: 60)
131
- # o = foo(:sedan, :turbo, page_len: 60)
132
- # o = foo(style: :sedan, page_len: 60)
133
- #=== Passing in option data:
134
- #The caller of this method may pass these options in a number of ways:
135
- #==== Array (via a splat)
136
- #Given the example shown in the new method, consider:
137
- # def test(count, *opt)
138
- # @opt_list.select(opt)
139
- # #etc, etc, etc...
140
- # end
141
- #With the caller now looking like:
142
- # test(43, :history)
143
- #==== Array (explicit)
144
- #An alternative strategy, where the use of splat is not desired, is to simply
145
- #have an array argument, as below:
146
- # def test(*arg1, opt)
147
- # @opt_list.select(opt)
148
- # #etc, etc, etc...
149
- # end
150
- #With the caller now looking like:
151
- # test(34, 53, 76, 'hike!', [:history])
152
- #==== Hash
153
- #Options may also be passed via a hash.
154
- # test(34, 53, 76, 'hike!', {:history=>:history, :page_len=>55})
155
- # test(34, 53, 76, 'hike!', history: :history, page_len: 55)
156
- #==== Symbol
157
- #If only a single option is required, it can be passed simply as:
158
- # test(34, 53, 76, 'hike!', :history)
59
+ #an access object for use in the code.
159
60
  #==== Parameters:
160
61
  #* selections - An array of the options passed into the client function, usually
161
62
  # with the splat operator. Note that if select is called with no arguments,
@@ -165,12 +66,25 @@ class OptionList
165
66
  #==== Exceptions:
166
67
  #* ArgumentError for a number of invalid argument conditions.
167
68
  #==== Notes:
168
- #After processing the selections, the selection validation block is called
69
+ #After processing the selections, the selection validation block is called
169
70
  #if one was defined for the constructor.
170
71
  def select(selections=[])
171
- selected = @default.clone
172
72
  selections = [selections] unless selections.is_a?(Array)
173
- dup = Set.new
73
+ selected = process_selections(selections)
74
+
75
+ @mandatory.each do |cat|
76
+ error "Missing mandatory setting #{cat}" unless selected[cat]
77
+ end
78
+
79
+ @select_block.call(selected) if @select_block
80
+ selected
81
+ end
82
+
83
+ private #Private stuff follows.
84
+
85
+ #Process a list of option selections.
86
+ def process_selections(selections)
87
+ selected, dup = @default.clone, Set.new
174
88
 
175
89
  selections.each do |opt|
176
90
  if opt.is_a?(Symbol)
@@ -178,104 +92,136 @@ class OptionList
178
92
  elsif opt.is_a?(Hash)
179
93
  hash_selections(opt, selected, dup)
180
94
  else
181
- fAE "Found #{opt.class} instead of Hash or Symbol."
95
+ error "Found #{opt.class} instead of Hash or Symbol."
182
96
  end
183
97
  end
184
-
185
- @mandatory.each do |cat|
186
- fAE "Missing mandatory setting #{cat}" unless selected[cat]
187
- end
188
-
189
- @select_block.call(selected) unless @select_block.nil?
98
+
190
99
  selected
191
100
  end
192
-
193
- private #Private stuff follows.
194
101
 
195
102
  #Return a internal category marker constant for value entries.
196
103
  def value_entry
197
104
  'A value entry.'
198
105
  end
199
-
106
+
200
107
  #Process an array spec that lists all the valid values for an option. See
201
108
  #the new method for more information on these specs.
202
109
  def array_spec(spec)
203
- cat = spec[0]
204
- spec = spec[1...spec.length]
205
-
206
- fAE "Found #{cat.class}, expected Symbol." unless cat.is_a?(Symbol)
207
- fAE "Duplicate category: #{cat}" if @default.has_key?(cat)
208
- fAE "Invalid number of entries for #{cat}." unless spec.length > 1
209
- @default.define_singleton_method(cat) { self[cat] }
210
-
211
- spec.each_with_index do |opt, index|
110
+ category, default, spec_len = spec[0], spec[1], spec.length
111
+ error "Invalid number of entries for #{category}." unless spec_len > 2
112
+ add_option_reader(category)
113
+ array_spec_default(category, default)
114
+ array_spec_tail_rest(category, spec[2...spec_len])
115
+ end
116
+
117
+ #Process the first element of the array spec tail.
118
+ def array_spec_default(category, opt)
119
+ opt && array_spec_single(category, opt)
120
+ @default[category] = opt
121
+ @mandatory << category if opt == false
122
+ end
123
+
124
+ #Process the rest of the array spec tail.
125
+ def array_spec_tail_rest(category, spec_tail_rest)
126
+ spec_tail_rest.each do |opt|
212
127
  if opt
213
- fAE "Found #{opt.class}, expected Symbol." unless opt.is_a?(Symbol)
214
- fAE "Duplicate option: #{opt}" if @categories.has_key?(opt)
215
-
216
- @categories[opt] = cat
217
- qry = (opt.to_s + '?').to_sym
218
- @default.define_singleton_method(qry) { self[cat] == opt }
219
- @default[cat] = opt if index == 0
220
- elsif index == 0
221
- @default[cat] = opt
222
- @mandatory << cat if opt == false
128
+ array_spec_single(category, opt)
223
129
  else
224
- fAE "The values nil/false are only allowed as the default option."
130
+ error "The values nil/false are only allowed as the default option."
225
131
  end
226
132
  end
227
133
  end
228
-
134
+
135
+ #Process a single array spec option
136
+ def array_spec_single(category, opt)
137
+ duplicate_entry_check(@categories, opt, 'option')
138
+ @categories[opt] = category
139
+ add_option_tester(category, opt)
140
+ end
141
+
229
142
  #Process a hash spec that lists only the default value for an option. See
230
143
  #the new method for more information on these specs.
231
144
  def hash_spec(spec)
232
- fAE "Hash contains no specs." unless spec.length > 0
145
+ error "Hash contains no specs." unless spec.length > 0
233
146
 
234
- spec.each do |cat, value|
235
- fAE "Found #{cat.class}, expected Symbol." unless cat.is_a?(Symbol)
236
- fAE "Duplicate category: #{cat}" if @default.has_key?(cat)
237
-
238
- @default.define_singleton_method(cat) { self[cat] }
239
- @categories[cat] = value_entry
240
- @default[cat] = value
147
+ spec.each do |category, value|
148
+ add_option_reader(category)
149
+ set_default_option_value(category, value)
150
+ @mandatory << category if value == false
241
151
  end
242
152
  end
243
-
153
+
154
+ #Set the default value of a value entry.
155
+ def set_default_option_value(category, value)
156
+ @categories[category] = value_entry
157
+ @default[category] = value
158
+ end
159
+
244
160
  #Process a symbolic option selection.
245
161
  #==== Parameters:
246
162
  #* option - a symbol to process.
247
163
  #* selected - a hash of selected data.
248
164
  #* dup - a set of categories that have been set. Used to detect duplicates.
249
- def symbolic_selection(option, selected, dup)
250
- fAE "Unknown option: #{option}." unless @categories.has_key?(option)
251
- cat = @categories[option]
252
- fAE "Category #{cat} has multiple values." if dup.include?(cat)
253
- dup.add(cat)
254
- selected[cat] = option
165
+ def symbolic_selection(symbol_option, selected, dup)
166
+ missing_entry_check(@categories, symbol_option, 'option')
167
+ category = @categories[symbol_option]
168
+ hash_option_dup_check(category, dup)
169
+ selected[category] = symbol_option
255
170
  end
256
-
171
+
257
172
  #Process a hash of option selection values.
258
173
  #==== Parameters:
259
174
  #* options - a hash of options to process.
260
175
  #* selected - a hash of selected data.
261
176
  #* dup - a set of categories that have been set. Used to detect duplicates.
262
- def hash_selections(options, selected, dup)
263
- options.each do |cat, value|
264
- fAE "Not a category: #{cat}." unless @default.has_key?(cat)
265
- fAE "Category #{cat} has multiple values." if dup.include?(cat)
266
-
267
- unless (@categories[cat] == value_entry) || value.nil?
268
- fAE "Found #{opt.class}, expected Symbol." unless value.is_a?(Symbol)
269
- fAE "Invalid option: #{value}." unless @categories[value] == cat
270
- end
271
-
272
- dup.add(cat)
273
- selected[cat] = value
177
+ def hash_selections(hash_options, selected, dup)
178
+ hash_options.each do |category, value|
179
+ missing_entry_check(@default, category, 'category')
180
+
181
+ hash_option_value_check(category, value)
182
+ hash_option_dup_check(category, dup)
183
+ selected[category] = value
184
+ end
185
+ end
186
+
187
+ #Validate a hash option value.
188
+ def hash_option_value_check(value_category, value)
189
+ if (@categories[value_category] != value_entry) && value
190
+ error "Found #{value.class}, expected Symbol." unless value.is_a?(Symbol)
191
+ error "Invalid option: #{value}." unless @categories[value] == value_category
274
192
  end
275
193
  end
276
194
 
195
+ #Add to set with no duplicates allowed.
196
+ def hash_option_dup_check(category, dup)
197
+ error "Category #{category} has multiple values." unless dup.add?(category)
198
+ end
199
+
200
+ #Add query method for the selected category.
201
+ def add_option_reader(name)
202
+ duplicate_entry_check(@default, name, 'category')
203
+ @default.define_singleton_method(name) { self[name] }
204
+ end
205
+
206
+ #Add a query method (eg: has_stuff? ) for the selected option.
207
+ def add_option_tester(target, value)
208
+ qry = (value.to_s + '?').to_sym
209
+ @default.define_singleton_method(qry) { self[target] == value}
210
+ end
211
+
212
+ #Flag any duplicate entry errors.
213
+ def duplicate_entry_check(target, entry, detail)
214
+ error "Found #{entry.class}, expected Symbol." unless entry.is_a?(Symbol)
215
+ error "Duplicate #{detail}: #{entry}" if target.has_key?(entry)
216
+ end
217
+
218
+ #Flag any missing entry errors.
219
+ def missing_entry_check(target, entry, detail)
220
+ error "Unknown #{detail}: #{entry}" unless target.has_key?(entry)
221
+ end
222
+
277
223
  #Fail with an argument error.
278
- def fAE(msg)
279
- fail(ArgumentError, msg, caller)
224
+ def error(messsage)
225
+ fail(ArgumentError, messsage, caller)
280
226
  end
281
227
  end
@@ -0,0 +1,3 @@
1
+ class OptionList
2
+ VERSION = '1.1.5'
3
+ end
data/license.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  === The MIT License (MIT).
2
2
 
3
- Copyright (c) 2013 Peter Camilleri
3
+ Copyright (c) 2013, 2014 Peter Camilleri
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ #Specify the building of the option_list gem.
4
+
5
+ lib = File.expand_path('../lib', __FILE__)
6
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
7
+ require 'option_list/version'
8
+
9
+ Gem::Specification.new do |s|
10
+ s.name = "option_list"
11
+ s.summary = "Flexible, Easy Function Parameters with Validation."
12
+ s.description = '[Deprecated] Flexible, Easy Function Parameters with Validation. '
13
+ s.version = OptionList::VERSION
14
+ s.author = ["Peter Camilleri"]
15
+ s.email = "peter.c.camilleri@gmail.com"
16
+ s.homepage = "http://teuthida-technologies.com/"
17
+ s.platform = Gem::Platform::RUBY
18
+ s.required_ruby_version = '>=1.9.3'
19
+
20
+ s.add_development_dependency "bundler", ">= 2.1.0"
21
+ s.add_development_dependency 'rake'
22
+ s.add_development_dependency 'reek', "~> 1.3.8"
23
+ s.add_development_dependency 'minitest', "~> 4.7.5"
24
+ s.add_development_dependency 'rdoc', "~> 4.0.1"
25
+ s.add_development_dependency 'awesome_print'
26
+
27
+ s.files = `git ls-files`.split($/)
28
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
29
+ s.extra_rdoc_files = ['license.txt']
30
+
31
+ s.license = 'MIT'
32
+ s.require_path = 'lib'
33
+ end
34
+
data/rakefile.rb CHANGED
@@ -1,11 +1,16 @@
1
1
  #!/usr/bin/env rake
2
+ # coding: utf-8
3
+
2
4
  require 'rake/testtask'
3
5
  require 'rdoc/task'
6
+ require "bundler/gem_tasks"
4
7
 
5
8
  RDoc::Task.new do |rdoc|
6
9
  rdoc.rdoc_dir = "rdoc"
7
- #rdoc.main = "option_list.rb"
8
- rdoc.rdoc_files = ['lib/option_list.rb', 'tests/option_list_test.rb', 'license.txt']
10
+
11
+ #List out all the files to be documented.
12
+ rdoc.rdoc_files.include("lib/**/*.rb", "license.txt", "README.md")
13
+
9
14
  rdoc.options << '--visibility' << 'private'
10
15
  end
11
16
 
@@ -13,3 +18,14 @@ Rake::TestTask.new do |t|
13
18
  t.test_files = ['tests/option_list_test.rb']
14
19
  t.verbose = false
15
20
  end
21
+
22
+ desc "Run a scan for smelly code!"
23
+ task :reek do |t|
24
+ `reek lib\\*.rb > reek.txt`
25
+ end
26
+
27
+ desc "What version of option_list is this?"
28
+ task :vers do |t|
29
+ puts
30
+ puts "option_list version = #{OptionList::VERSION}"
31
+ end
data/reek.txt ADDED
@@ -0,0 +1 @@
1
+ lib/option_list.rb -- 0 warnings
data/sire.rb ADDED
@@ -0,0 +1,51 @@
1
+ # Really simple program # 3
2
+ # A Simple Interactive Ruby Environment
3
+ # SIRE Version 0.2.6
4
+
5
+ require 'readline'
6
+ require 'awesome_print'
7
+ require_relative 'lib/option_list'
8
+ include Readline
9
+
10
+ class Object
11
+ def classes
12
+ begin
13
+ klass = self
14
+
15
+ begin
16
+ klass = klass.class unless klass.instance_of?(Class)
17
+ print klass
18
+ klass = klass.superclass
19
+ print " < " if klass
20
+ end while klass
21
+
22
+ puts
23
+ end
24
+ end
25
+ end
26
+
27
+ def show_args(*args)
28
+ args
29
+ end
30
+
31
+ puts "Welcome to SIRE Version 0.2.6"
32
+ puts "Simple Interactive Ruby Environment"
33
+ done = false
34
+
35
+ until done
36
+ begin
37
+ line = readline('SIRE>', true)
38
+ result = eval line
39
+ ap result unless result.nil?
40
+ rescue Interrupt
41
+ done = true
42
+ rescue Exception => e
43
+ puts "#{e.class} detected: #{e}"
44
+ puts e.backtrace
45
+ puts
46
+ end
47
+ end
48
+
49
+ puts
50
+ puts "Bye bye for now!"
51
+
@@ -8,73 +8,73 @@ class OptionTest
8
8
  def initialize(opt)
9
9
  @opt = opt
10
10
  end
11
-
11
+
12
12
  def test(*args)
13
- o = @opt.select(args)
13
+ @opt.select(args)
14
14
  end
15
15
  end
16
16
 
17
- class OptionListTester < MiniTest::Unit::TestCase
17
+ class OptionListTester < Minitest::Test
18
18
  $do_this_only_one_time = ""
19
-
19
+
20
20
  def initialize(*all)
21
21
  if $do_this_only_one_time != __FILE__
22
22
  puts
23
- puts "Running test file: #{File.split(__FILE__)[1]}"
23
+ puts "Running test file: #{File.split(__FILE__)[1]}"
24
24
  $do_this_only_one_time = __FILE__
25
25
  end
26
-
26
+
27
27
  super(*all)
28
28
  end
29
29
 
30
30
  def test_that_it_rejects_bad_specs
31
31
  #Reject empty argument lists.
32
- assert_raises(ArgumentError) { @x = OptionList.new }
32
+ assert_raises(ArgumentError) { @x = OptionList.new }
33
33
  assert_raises(ArgumentError) { @x = OptionList.new([])}
34
34
  assert_raises(ArgumentError) { @x = OptionList.new({})}
35
-
35
+
36
36
  #Reject if not an array or a hash.
37
37
  assert_raises(ArgumentError) { @x = OptionList.new(4) }
38
- assert_raises(ArgumentError) { @x = OptionList.new('foobar') }
38
+ assert_raises(ArgumentError) { @x = OptionList.new('foobar') }
39
39
 
40
40
  #Reject for too few arguments.
41
41
  assert_raises(ArgumentError) { @x = OptionList.new([]) }
42
42
  assert_raises(ArgumentError) { @x = OptionList.new([:foo]) }
43
43
  assert_raises(ArgumentError) { @x = OptionList.new([:foo, :bar]) }
44
-
44
+
45
45
  #Reject for the wrong types of arguments.
46
46
  assert_raises(ArgumentError) { @x = OptionList.new(['foo', :foo, :bar] )}
47
47
  assert_raises(ArgumentError) { @x = OptionList.new([:foo, 'foo', :bar] )}
48
48
  assert_raises(ArgumentError) { @x = OptionList.new([:foo, :foo, 'bar'])}
49
49
  assert_raises(ArgumentError) { @x = OptionList.new({'foo' => 42})}
50
-
50
+
51
51
  #Reject for duplicate categories.
52
52
  assert_raises(ArgumentError) { @x = OptionList.new([:foo, :lala, :bar], [:foo, :kung, :east]) }
53
53
  assert_raises(ArgumentError) { @x = OptionList.new([:foo, :lala, :bar], {:foo => :kung}) }
54
54
  assert_raises(ArgumentError) { @x = OptionList.new({:foo => :lala}, {:foo => :kung}) }
55
55
  #The following is not detectable since :foo => :kung overwrites :foo => :lala
56
56
  #assert_raises(ArgumentError) { @x = OptionList.new({:foo => :lala, :foo => :kung}) }
57
-
57
+
58
58
  #Reject for duplicate options.
59
59
  assert_raises(ArgumentError) { @x = OptionList.new([:foo, :bar, :bar]) }
60
- assert_raises(ArgumentError) { @x = OptionList.new([:foo, :foo, :bar], [:bla, :food, :bar]) }
60
+ assert_raises(ArgumentError) { @x = OptionList.new([:foo, :foo, :bar], [:bla, :food, :bar]) }
61
61
 
62
- #Reject for nil in the wrong position.
62
+ #Reject for nil in the wrong position.
63
63
  assert_raises(ArgumentError) { @x = OptionList.new([:foo, :bar, nil]) }
64
64
  end
65
-
65
+
66
66
  def test_that_the_methods_were_added
67
67
  ol1 = OptionList.new([:history, :history, :nohistory], {:pg_len => 42})
68
68
  o = ol1.select
69
-
69
+
70
70
  assert_respond_to(o, :history)
71
71
  assert_respond_to(o, :history? )
72
72
  assert_respond_to(o, :nohistory? )
73
73
  assert_respond_to(o, :pg_len)
74
74
 
75
- ol2 = OptionList.new([:history, nil, :history, :nohistory])
75
+ ol2 = OptionList.new([:history, nil, :history, :nohistory])
76
76
  o = ol2.select
77
-
77
+
78
78
  assert_respond_to(o, :history)
79
79
  assert_respond_to(o, :history? )
80
80
  assert_respond_to(o, :nohistory? )
@@ -83,76 +83,76 @@ class OptionListTester < MiniTest::Unit::TestCase
83
83
 
84
84
  def test_that_it_rejects_bad_selections
85
85
  ol1 = OptionList.new([:history, :history, :nohistory], {:pg_len => 42})
86
-
86
+
87
87
  #Reject if options are not an array or a hash.
88
88
  assert_raises(ArgumentError) { ol1.select(45) }
89
-
89
+
90
90
  #Reject if the option is not a symbol.
91
91
  assert_raises(ArgumentError) { ol1.select([34]) }
92
-
92
+
93
93
  #Reject if the category is not a symbol.
94
94
  assert_raises(ArgumentError) { ol1.select({'page_len'=>77}) }
95
-
95
+
96
96
  #Reject if the symbol is not one defined.
97
97
  assert_raises(ArgumentError) { ol1.select([:foobar]) }
98
98
  assert_raises(ArgumentError) { ol1.select({:history=>:foobar}) }
99
-
99
+
100
100
  #Reject on duplicate symbol from the same category.
101
101
  assert_raises(ArgumentError) { ol1.select([:history, :history]) }
102
- assert_raises(ArgumentError) { ol1.select([:history, :nohistory]) }
102
+ assert_raises(ArgumentError) { ol1.select([:history, :nohistory]) }
103
103
  assert_raises(ArgumentError) { ol1.select([:history, {:history=>:nohistory}]) }
104
104
  assert_raises(ArgumentError) { ol1.select([{:history=>:history}, {:history=>:nohistory}]) }
105
-
105
+
106
106
  #Reject on an undefined category.
107
107
  assert_raises(ArgumentError) { ol1.select({:zoo => 999})}
108
108
  end
109
-
109
+
110
110
  def test_that_it_handles_good_options
111
111
  #ol1 test series.
112
112
  ol1 = OptionList.new([:history, :history, :nohistory], {:pg_len => 42})
113
-
113
+
114
114
  o = ol1.select
115
115
  assert(o.history?)
116
116
  refute(o.nohistory?)
117
117
  assert_equal(o.history, :history)
118
- assert_equal(o.pg_len, 42)
119
-
118
+ assert_equal(o.pg_len, 42)
119
+
120
120
  o = ol1.select([])
121
121
  assert(o.history?)
122
122
  refute(o.nohistory?)
123
123
  assert_equal(o.history, :history)
124
- assert_equal(o.pg_len, 42)
125
-
124
+ assert_equal(o.pg_len, 42)
125
+
126
126
  o = ol1.select([:history])
127
127
  assert(o.history?)
128
128
  refute(o.nohistory?)
129
129
  assert_equal(o.history, :history)
130
- assert_equal(o.pg_len, 42)
131
-
130
+ assert_equal(o.pg_len, 42)
131
+
132
132
  o = ol1.select([:nohistory])
133
133
  refute(o.history?)
134
134
  assert(o.nohistory?)
135
135
  assert_equal(o.history, :nohistory)
136
- assert_equal(o.pg_len, 42)
136
+ assert_equal(o.pg_len, 42)
137
137
 
138
138
  o = ol1.select({:history=>:history})
139
139
  assert(o.history?)
140
140
  refute(o.nohistory?)
141
141
  assert_equal(o.history, :history)
142
- assert_equal(o.pg_len, 42)
143
-
142
+ assert_equal(o.pg_len, 42)
143
+
144
144
  o = ol1.select({:history=>:nohistory})
145
145
  refute(o.history?)
146
146
  assert(o.nohistory?)
147
147
  assert_equal(o.history, :nohistory)
148
- assert_equal(o.pg_len, 42)
148
+ assert_equal(o.pg_len, 42)
149
149
 
150
150
  o = ol1.select({:pg_len=>55})
151
151
  assert(o.history?)
152
152
  refute(o.nohistory?)
153
153
  assert_equal(o.history, :history)
154
154
  assert_equal(o.pg_len, 55)
155
-
155
+
156
156
  o = ol1.select({:history=>:history, :pg_len=>55})
157
157
  assert(o.history?)
158
158
  refute(o.nohistory?)
@@ -177,10 +177,10 @@ class OptionListTester < MiniTest::Unit::TestCase
177
177
  assert_equal(o.history, :nohistory)
178
178
  assert_equal(o.pg_len, 55)
179
179
 
180
-
180
+
181
181
  #ol2 test series.
182
- ol2 = OptionList.new([:history, nil, :history, :nohistory])
183
-
182
+ ol2 = OptionList.new([:history, nil, :history, :nohistory])
183
+
184
184
  o = ol2.select([:history])
185
185
  assert(o.history?)
186
186
  refute(o.nohistory?)
@@ -196,9 +196,9 @@ class OptionListTester < MiniTest::Unit::TestCase
196
196
  refute(o.nohistory?)
197
197
  assert(o.history.nil?)
198
198
  end
199
-
199
+
200
200
  def test_that_mandatory_parms_work
201
- ol2 = OptionList.new([:history, false, :history, :nohistory])
201
+ ol2 = OptionList.new([:history, false, :history, :nohistory])
202
202
 
203
203
  o = ol2.select([:history])
204
204
  assert(o.history?)
@@ -211,24 +211,30 @@ class OptionListTester < MiniTest::Unit::TestCase
211
211
  assert_equal(o.history, :nohistory)
212
212
 
213
213
  assert_raises(ArgumentError) { ol2.select() }
214
+
215
+ ol3 = OptionList.new(page_len: false)
216
+ o = ol3.select(page_len: 42)
217
+ assert_equal(o.page_len, 42)
218
+
219
+ assert_raises(ArgumentError) { ol3.select() }
214
220
  end
215
-
221
+
216
222
  def test_that_it_does_not_munge_parms
217
223
  parm1 = [:history, false, :history, :nohistory]
218
224
  parm2 = parm1.clone
219
- ol2 = OptionList.new(parm1)
225
+ OptionList.new(parm1)
220
226
  assert_equal(parm1, parm2)
221
227
  end
222
-
228
+
223
229
  def test_that_the_select_block_works
224
230
  ol3 = OptionList.new([:history, nil, :history, :nohistory],
225
231
  fuel1: :matter, fuel2: :antimatter) do |opt|
226
232
  fail "The :history option must be set." if opt.history.nil?
227
233
  fail "Improper fuel mix." unless opt.fuel1 == :matter && opt.fuel2 == :antimatter
228
234
  end
229
-
235
+
230
236
  t = OptionTest.new(ol3)
231
-
237
+
232
238
  assert_raises(RuntimeError) { t.test() }
233
239
  assert_raises(RuntimeError) { t.test(:nohistory, fuel2: :income_tax) }
234
240
  #Really though, this should work! Both anti-matter and income tax
metadata CHANGED
@@ -1,54 +1,121 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: option_list
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Camilleri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-20 00:00:00.000000000 Z
11
+ date: 2021-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.1.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.1.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rake
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
- - - ! '>='
31
+ - - ">="
18
32
  - !ruby/object:Gem::Version
19
33
  version: '0'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
- - - ! '>='
38
+ - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: reek
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3.8
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.8
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: minitest
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
- - - ! '>='
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 4.7.5
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 4.7.5
69
+ - !ruby/object:Gem::Dependency
70
+ name: rdoc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 4.0.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 4.0.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: awesome_print
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
32
88
  - !ruby/object:Gem::Version
33
89
  version: '0'
34
90
  type: :development
35
91
  prerelease: false
36
92
  version_requirements: !ruby/object:Gem::Requirement
37
93
  requirements:
38
- - - ! '>='
94
+ - - ">="
39
95
  - !ruby/object:Gem::Version
40
96
  version: '0'
41
- description: ! 'A unified handler for flexible function option parameters. '
97
+ description: "[Deprecated] Flexible, Easy Function Parameters with Validation. "
42
98
  email: peter.c.camilleri@gmail.com
43
99
  executables: []
44
100
  extensions: []
45
101
  extra_rdoc_files:
46
102
  - license.txt
47
103
  files:
104
+ - ".gitignore"
105
+ - CODE_OF_CONDUCT.md
106
+ - Gemfile
107
+ - README.md
108
+ - docs/OL_UG.odt
109
+ - docs/OL_UG.pdf
110
+ - docs/OL_UG_Version_1_1_1.pdf
48
111
  - lib/option_list.rb
49
- - tests/option_list_test.rb
50
- - rakefile.rb
112
+ - lib/option_list/version.rb
51
113
  - license.txt
114
+ - option_list.gemspec
115
+ - rakefile.rb
116
+ - reek.txt
117
+ - sire.rb
118
+ - tests/option_list_test.rb
52
119
  homepage: http://teuthida-technologies.com/
53
120
  licenses:
54
121
  - MIT
@@ -59,19 +126,17 @@ require_paths:
59
126
  - lib
60
127
  required_ruby_version: !ruby/object:Gem::Requirement
61
128
  requirements:
62
- - - ! '>='
129
+ - - ">="
63
130
  - !ruby/object:Gem::Version
64
131
  version: 1.9.3
65
132
  required_rubygems_version: !ruby/object:Gem::Requirement
66
133
  requirements:
67
- - - ! '>='
134
+ - - ">="
68
135
  - !ruby/object:Gem::Version
69
136
  version: '0'
70
137
  requirements: []
71
- rubyforge_project:
72
- rubygems_version: 2.1.4
138
+ rubygems_version: 3.2.17
73
139
  signing_key:
74
140
  specification_version: 4
75
- summary: A unified handler for flexible function option parameters.
76
- test_files:
77
- - tests/option_list_test.rb
141
+ summary: Flexible, Easy Function Parameters with Validation.
142
+ test_files: []