opensecret 0.0.988 → 0.0.9925

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 (62) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +56 -159
  3. data/bin/opensecret +2 -2
  4. data/bin/ops +17 -2
  5. data/lib/extension/string.rb +14 -16
  6. data/lib/{interpreter.rb → interprete.rb} +53 -29
  7. data/lib/keytools/binary.map.rb +49 -0
  8. data/lib/keytools/kdf.api.rb +249 -0
  9. data/lib/keytools/kdf.bcrypt.rb +64 -29
  10. data/lib/keytools/kdf.pbkdf2.rb +92 -83
  11. data/lib/keytools/kdf.scrypt.rb +190 -0
  12. data/lib/keytools/key.64.rb +326 -0
  13. data/lib/keytools/key.algo.rb +109 -0
  14. data/lib/keytools/key.api.rb +1281 -0
  15. data/lib/keytools/key.db.rb +265 -0
  16. data/lib/keytools/{key.module.rb → key.docs.rb} +55 -0
  17. data/lib/keytools/key.error.rb +110 -0
  18. data/lib/keytools/key.id.rb +271 -0
  19. data/lib/keytools/key.iv.rb +107 -0
  20. data/lib/keytools/key.local.rb +265 -0
  21. data/lib/keytools/key.mach.rb +248 -0
  22. data/lib/keytools/key.now.rb +402 -0
  23. data/lib/keytools/key.pair.rb +259 -0
  24. data/lib/keytools/key.pass.rb +120 -0
  25. data/lib/keytools/key.rb +428 -298
  26. data/lib/keytools/keydebug.txt +295 -0
  27. data/lib/logging/gem.logging.rb +3 -3
  28. data/lib/modules/cryptology/collect.rb +20 -0
  29. data/lib/session/require.gem.rb +1 -1
  30. data/lib/usecase/cmd.rb +417 -0
  31. data/lib/usecase/id.rb +36 -0
  32. data/lib/usecase/import.rb +174 -0
  33. data/lib/usecase/init.rb +78 -0
  34. data/lib/usecase/login.rb +70 -0
  35. data/lib/usecase/logout.rb +30 -0
  36. data/lib/usecase/open.rb +126 -0
  37. data/lib/{interprete → usecase}/put.rb +100 -47
  38. data/lib/usecase/read.rb +89 -0
  39. data/lib/{interprete → usecase}/safe.rb +0 -0
  40. data/lib/{interprete → usecase}/set.rb +0 -0
  41. data/lib/usecase/token.rb +111 -0
  42. data/lib/{interprete → usecase}/use.rb +0 -0
  43. data/lib/version.rb +1 -1
  44. data/opensecret.gemspec +4 -3
  45. metadata +39 -33
  46. data/lib/exception/cli.error.rb +0 -53
  47. data/lib/exception/errors/cli.errors.rb +0 -31
  48. data/lib/interprete/begin.rb +0 -232
  49. data/lib/interprete/cmd.rb +0 -621
  50. data/lib/interprete/export.rb +0 -163
  51. data/lib/interprete/init.rb +0 -205
  52. data/lib/interprete/key.rb +0 -119
  53. data/lib/interprete/open.rb +0 -148
  54. data/lib/interprete/seal.rb +0 -129
  55. data/lib/keytools/digester.rb +0 -245
  56. data/lib/keytools/key.data.rb +0 -227
  57. data/lib/keytools/key.derivation.rb +0 -341
  58. data/lib/modules/mappers/collateral.rb +0 -282
  59. data/lib/modules/mappers/envelope.rb +0 -127
  60. data/lib/modules/mappers/settings.rb +0 -170
  61. data/lib/notepad/scratch.pad.rb +0 -224
  62. data/lib/store-commands.txt +0 -180
@@ -0,0 +1,402 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenKey
4
+
5
+ require 'singleton'
6
+
7
+ # This stamp sits at the centre of a fundamental DevOps pattern concerned
8
+ # with infrastructure provisioning and configuraion management.
9
+ #
10
+ # The central idea behind the pattern is to link every infrastructure
11
+ # object created during a session with a reference accurate to the nearest
12
+ # centi-second denoting the moment the software runtime (session) began.
13
+ class KeyNow
14
+ include Singleton
15
+
16
+ attr_reader :time_now
17
+
18
+ # Return two digit [mo] month index from 01 to 12.
19
+ # @example 02 => in February
20
+ #
21
+ def self.mo
22
+ return KeyNow.instance.time_now.strftime "%m"
23
+ end
24
+
25
+
26
+ # Return three character abbreviated month name.
27
+ # @example feb => in February
28
+ #
29
+ def self.mmm
30
+ return KeyNow.instance.time_now.strftime( "%b" ).downcase
31
+ end
32
+
33
+
34
+ #
35
+ # Return three character abbreviated day of week.
36
+ # @example tue => on Tuesday
37
+ #
38
+ def self.ddd
39
+ return KeyNow.instance.time_now.strftime( "%a" ).downcase
40
+ end
41
+
42
+
43
+ #
44
+ # Return two digit (character) hour of day from 00 to 23.
45
+ # @example 22 => between 22.00.00 and 22.59.59 inclusive
46
+ #
47
+ def self.hh
48
+ return KeyNow.instance.time_now.strftime "%H"
49
+ end
50
+
51
+
52
+ #
53
+ # Return two digit minute of hour from [00] to [59].
54
+ #
55
+ def self.mm
56
+ return KeyNow.instance.time_now.strftime "%M"
57
+ end
58
+
59
+
60
+ #
61
+ # Return two digit second of minute from [00] to [59].
62
+ #
63
+ def self.ss
64
+ return KeyNow.instance.time_now.strftime "%S"
65
+ end
66
+
67
+
68
+ #
69
+ # Return a [3 digit] second and tenth of second
70
+ # representation.
71
+ #
72
+ # The final digit is derived from the 1000 sliced
73
+ # millisecond of second running from 000 to 999.
74
+ #
75
+ # <tt>Truncation (Not Rounding)</tt>
76
+ #
77
+ # The [final] digit is acquired by TRUNCATING
78
+ # (chopping off) the last 2 of the 3 millisecond
79
+ # digits. No rounding is applied.
80
+ #
81
+ # The 3 returned digits comprise of the
82
+ #
83
+ # - second of minute => 2 digits | [00] to [59] (and)
84
+ # - tenth of second => 1 digit from [0] to [9]
85
+ #
86
+ # @example
87
+ #
88
+ # => The time at the 562nd millisecond of the 49th
89
+ # second of the minute.
90
+ #
91
+ # => 3 chars
92
+ # => 495
93
+ #
94
+ #
95
+ def self.sst
96
+ millisec_string = KeyNow.instance.time_now.strftime "%L"
97
+ return "#{ss}#{millisec_string[0]}"
98
+ end
99
+
100
+
101
+ #
102
+ # Return the [two] digit year (eg 19 for 2019).
103
+ # that we are currently in.
104
+ #
105
+ def self.yy
106
+ return KeyNow.instance.time_now.strftime("%Y")[2..-1]
107
+ end
108
+
109
+
110
+ #
111
+ # Return the [four] digit year (eg 2019)
112
+ # that we are currently in.
113
+ #
114
+ def self.yyyy
115
+ return KeyNow.instance.time_now.strftime("%Y")
116
+ end
117
+
118
+
119
+ # ------------------------------------------------- -- #
120
+ # Return 3 digit julian day of year [001] to [366]. -- #
121
+ # ------------------------------------------------- -- #
122
+ def self.jjj
123
+ return KeyNow.instance.time_now.strftime "%j"
124
+ end
125
+
126
+
127
+ # [yymo_mmm] returns an amalgam of
128
+ #
129
+ # => the two-digit year
130
+ # => the two-digit month index (starting at 01)
131
+ # => a period (separator)
132
+ # => the abbreviated month name
133
+ #
134
+ # @example
135
+ # => 1908.aug
136
+ # => for August 2019
137
+ #
138
+ def self.yymo_mmm
139
+ return "#{yy}#{mo}.#{mmm}"
140
+ end
141
+
142
+
143
+ #
144
+ # Given two integer parameters (month index and 4 digit year) representing
145
+ # the month in question this method returns the [PREVIOUS MONTHS] character
146
+ # amalgam in the format [yymo_mmm] where
147
+ #
148
+ # => yy | previous month's two-digit year
149
+ # => mo | previous month's two-digit month index
150
+ # => . | a period (separator)
151
+ # => mmm | previous month's abbreviated month name
152
+ #
153
+ # -------------------
154
+ # Example 1 (Simple)
155
+ # -------------------
156
+ #
157
+ # returns char => 1907.jul
158
+ # 4 parameters => 8, 2019
159
+ # representing => August, 2019
160
+ #
161
+ # ----------------------
162
+ # Example 2 (Last Year)
163
+ # ----------------------
164
+ #
165
+ # returns char => 1812.dec
166
+ # 4 parameters => 1, 2019
167
+ # representing => January, 2019
168
+ #
169
+ def self.previous_month_chars this_month_index, this_4digit_year
170
+
171
+ prev_month_index = this_month_index == 1 ? 12 : ( this_month_index - 1 )
172
+ prev_2dig_mn_pad = sprintf '%02d', prev_month_index
173
+ prev_4digit_year = this_month_index == 1 ? ( this_4digit_year - 1 ) : this_4digit_year
174
+ prev_twodigit_yr = "#{prev_4digit_year.to_s}"[2..-1]
175
+ prev_months_name = Date::ABBR_MONTHNAMES[prev_month_index].downcase
176
+
177
+ return "#{prev_twodigit_yr}#{prev_2dig_mn_pad}.#{prev_months_name}"
178
+
179
+ end
180
+
181
+ #
182
+ # Using the current class time this method returns
183
+ # the character amalgam for the [PREVIOUS MONTH] in
184
+ # the format [yymo_mmm] where
185
+ #
186
+ # => yy | last month's two-digit year
187
+ # => mo | last month's two-digit month index
188
+ # => . | a period (separator)
189
+ # => mmm | last month's abbreviated month name
190
+ #
191
+ # -------------------
192
+ # Example 1 (Simple)
193
+ # -------------------
194
+ #
195
+ # returns => 1907.jul
196
+ # if this month is => August 2019
197
+ #
198
+ # ----------------------
199
+ # Example 2 (Last Year)
200
+ # ----------------------
201
+ #
202
+ # returns => 1812.dec
203
+ # if this month is => January 2019
204
+ #
205
+ def self.yymo_mmm_prev
206
+ return previous_month_chars mo.to_i, yyyy.to_i
207
+ end
208
+
209
+
210
+ # Return 5 digit amalgam of year and julian day.
211
+ # eg [19003] for [January 3rd 2019]
212
+ def self.yyjjj
213
+ return "#{yy}#{jjj}"
214
+ end
215
+
216
+
217
+ # Return the 4 digit amalgam of the hour and minute
218
+ # using the 24 hour clock.
219
+ #
220
+ # @example
221
+ # => 1525
222
+ # => 03:25 pm
223
+ #
224
+ def self.hhmm
225
+ return "#{hh}#{mm}"
226
+ end
227
+
228
+
229
+ #
230
+ # Return the time of day to a TENTH of a second accuracy.
231
+ # [8] characters will always be returned with the 5th one
232
+ # being the (period) separator.
233
+ #
234
+ # The first (separated) segment delivers a hhmm 24 hour
235
+ # clock representation of the stamped time.
236
+ #
237
+ # The 3 digits of the second segment comprise of
238
+ #
239
+ # second of minute => 2 digits | [00] to [59]
240
+ # tenth of second => 1 digit from [0] to [9]
241
+ #
242
+ # @example
243
+ # => The time at the 562nd millisecond of the 49th
244
+ # second of the 23rd minute of the 17th hour of
245
+ # the day ( 17:23:49.562 )
246
+ #
247
+ # => 8 chars
248
+ # => 1723.495
249
+ #
250
+ def self.hhmm_sst
251
+ return "#{hhmm}.#{sst}"
252
+ end
253
+
254
+
255
+ # Return a string timestampt that is a period separated
256
+ # amalgam of the 2 digit year, 3 digit julian day, 2 digit
257
+ # hour, 2 digit minute, 2 digit second and 1 digit rounded
258
+ # down tenth of second.
259
+ #
260
+ # @example
261
+ # => 19003.1025
262
+ # => 10:25 am on January 3rd 2019
263
+ #
264
+ #
265
+ # Return the time of day to a TENTH of a second accuracy.
266
+ # [8] characters will always be returned with the 5th one
267
+ # being the (period) separator.
268
+ #
269
+ # The first (separated) segment delivers a hhmm 24 hour
270
+ # clock representation of the stamped time.
271
+ #
272
+ # The 3 digits of the second segment comprise of
273
+ #
274
+ # - second of minute => 2 digits | [00] to [59]
275
+ # - tenth of second => 1 digit from [0] to [9]
276
+ #
277
+ # @example
278
+ # => The time at the 562nd millisecond of the 49th
279
+ # second of the 23rd minute of the 17th hour of
280
+ # the day ( 17:23:49.562 )
281
+ #
282
+ # => 8 chars
283
+ # => 1723.495
284
+ #
285
+ def self.yyjjj_hhmm_sst
286
+ return "#{yyjjj}.#{hhmm}.#{sst}"
287
+ end
288
+
289
+
290
+ # Return a string timestampt that is a period separated
291
+ # amalgam of the 2 digit year, 3 digit julian day, 2 digit
292
+ # hour, 2 digit minute, 2 digit second and <b>9 digit</b>
293
+ # nanosecond.
294
+ #
295
+ # @example
296
+ # return => 19003.1725.42.836592034
297
+ # 4 time => 17:25:42 am on January 3rd 2019
298
+ #
299
+ # As per the above example, the time returned
300
+ #
301
+ # - is the 836592034 <b>nanosecond</b>
302
+ # - of the 42nd <b>second</b>
303
+ # - of the 25th <b>minute</b>
304
+ # - of the 17th <b>hour</b>
305
+ # - of the 3rd <b>day</b>
306
+ # - of the 20th <b>year</b>
307
+ # - of the 21st <b>century</b>
308
+ #
309
+ # @return [String]
310
+ # Return the time of day to nanosecond accuracy.
311
+ # 23 characters are always returned with three (3) period
312
+ # separators at the 6th, 11th and 14th positions.
313
+ def self.yyjjj_hhmm_ss_nanosec
314
+ nanosec_str = KeyNow.instance.time_now.strftime "%9N"
315
+ return "#{yyjjj}.#{hhmm}.#{ss}.#{nanosec_str}"
316
+ end
317
+
318
+
319
+ # Fetch the double barreled time stamp that is an amalgam of
320
+ # the human readable time now and a machine time representation
321
+ # from the moment this class was initialized.
322
+ #
323
+ # See the {yyjjj_hhmm_ss_nanosec} method for documentation of
324
+ # the nanosecond accurate time stamp.
325
+ #
326
+ # @return [String]
327
+ # the double barreled time stamp containing a human readable
328
+ # (right this moment) time and a <b>class initialized time</b>
329
+ # representation with nanosecond accuracy.
330
+ def self.fetch
331
+ return "#{Time.now.ctime} ( #{yyjjj_hhmm_ss_nanosec} )"
332
+ end
333
+
334
+
335
+ # Grab the double barreled time stamp that is an amalgam of
336
+ # the human readable time now and a machine time representation
337
+ # from the moment this class was initialized.
338
+ #
339
+ # On Friday June the 8th at about 6:26 pm.
340
+ # Fri Jun 8 18:26:17 2018 ( 18159.1826.138 )
341
+ #
342
+ # See the {yyjjj_hhmm_sst} method for documentation of stamp
343
+ # that is accurate to the tenth of a second.
344
+ #
345
+ # @return [String]
346
+ # the double barreled time stamp containing a human readable
347
+ # (right this moment) time and a <b>class initialized time</b>
348
+ # representation with tenth of a second accuracy.
349
+ def self.grab
350
+ time_with_consecutive_spaces = Time.now.ctime
351
+ human_readable_str = time_with_consecutive_spaces.gsub( " ", " " )
352
+ return "#{human_readable_str} ( #{yyjjj_hhmm_sst} )"
353
+ end
354
+
355
+
356
+ # Return the Rubyfied time zone being used.
357
+ def self.zone
358
+ return KeyNow.instance.time_now.zone
359
+ end
360
+
361
+
362
+ # Log segments of time pertaining to the time stamp.
363
+ # @todo
364
+ # move method contents into test class
365
+ def self.log_instance_time
366
+
367
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
368
+ log.info(x) { "[stamp] eco time stamp => [#{KeyNow.instance.time_now.ctime}]" }
369
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
370
+ log.info(x) { "[stamp] Univ Time Zone => #{zone}" }
371
+ log.info(x) { "[stamp] Month Index is => #{mo}" }
372
+ log.info(x) { "[stamp] Month Name is => #{mmm}" }
373
+ log.info(x) { "[stamp] Day Of Week is => #{ddd}" }
374
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
375
+ log.info(x) { "[stamp] Two Digit Year => #{yy}" }
376
+ log.info(x) { "[stamp] Julian Cal Day => #{jjj}" }
377
+ log.info(x) { "[stamp] Yr and Jul Day => #{yyjjj}" }
378
+ log.info(x) { "[stamp] Hour of Theday => #{hh}" }
379
+ log.info(x) { "[stamp] Minute of Hour => #{mm}" }
380
+ log.info(x) { "[stamp] Hour + Minute => #{hhmm}" }
381
+ log.info(x) { "[stamp] Second of Min => #{ss}" }
382
+ log.info(x) { "[stamp] 600 Min Slices => #{sst}" }
383
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
384
+ log.info(x) { "[stamp] The Time Stamp => #{yyjjj_hhmm_sst}" }
385
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
386
+
387
+ end
388
+
389
+
390
+ # This singleton (one instance) class sets the time just once.
391
+ def initialize
392
+ @time_now = Time.now;
393
+ end
394
+
395
+
396
+ KeyNow.log_instance_time
397
+
398
+
399
+ end
400
+
401
+
402
+ end
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module OpenKey
5
+
6
+ require 'inifile'
7
+
8
+ # KeyPair is a <b>key-value</b> store backed by a plain-text file in
9
+ # an <b>INI format</b> that sits on an accessible file-system.
10
+ #
11
+ #
12
+ # == Example Data Exchange
13
+ #
14
+ # Issue the below ruby calls and specify a /path/to/file
15
+ #
16
+ # keymap = KeyPair.new "/path/to/file"
17
+ #
18
+ # keymap.use "phone_numbers"
19
+ # keymap.set "joe", "0044 7500 123456"
20
+ # keymap.set "amy", "0044 7678 123456"
21
+ #
22
+ # Now visit the file to see your exchanged data.
23
+ #
24
+ # [phone_numbers]
25
+ # joe = 0044 7500 123456
26
+ # amy = 0044 7678 123456
27
+ #
28
+ #
29
+ # == The <em>Current</em> Section
30
+ #
31
+ # You can set the <b>current section</b> with the {use} method and then
32
+ # subsequent read, write, or query behaviour will reference the section that
33
+ # you stated.
34
+ #
35
+ # You do not need a new object to switch sections - just go ahead and
36
+ # use another another one.
37
+ #
38
+ # Remember that KeyPair is <b>two-dimensional</b> data structure so all
39
+ # key-value pairs are stored under the auspices of a section.
40
+ #
41
+ # == Key-Value Pair Exchanges
42
+ #
43
+ # Representational state transfer occurs with four methods with
44
+ #
45
+ # - custom sections referenced through {read} and {write}
46
+ # - said sections transfered via ubiquitous {get} and {set}
47
+ #
48
+ # The name given to the default group can be specified to the constructor.
49
+ # If none is provided the aptly named "default" is used.
50
+ class KeyPair
51
+
52
+ # Initialize the key value store and auto write a time stamp that
53
+ # has nano-second accuracy with a key whose name is gleened from
54
+ # the constant {KeyData::INIT_TIME_STAMP_NAME}.
55
+ #
56
+ # The path to the backing INI file is gleened from the first
57
+ # backing file path parameter.
58
+ #
59
+ # @param backing_file_path [String]
60
+ # the expected location of the file-backed key-value store.
61
+ # If the folder and/or file do not exist the folder is created
62
+ # and then the file is created along with the time stamps.
63
+ #
64
+ # @param the_default_group [String]
65
+ # the name of the default group. If none is presented this value
66
+ # will default to the aptly named "default".
67
+ def initialize backing_file_path
68
+ @file_path = backing_file_path
69
+ create_dir_if_necessary
70
+ end
71
+
72
+
73
+ # Set the section to use for future data exchanges via the ubiquitous {get}
74
+ # and {set} methods as well as the query {contains} key method.
75
+ #
76
+ # @param the_section_name [String]
77
+ # the non-nil and non whitespace only section name that will lead a
78
+ # set of key-value pairs in the INI formatted file.
79
+ def use the_section_name
80
+ raise ArgumentError, "Cannot use a Nil section name." if the_section_name.nil?
81
+ @section_to_use = the_section_name
82
+ end
83
+
84
+ # Stash the setting directive and its value into the configuration file
85
+ # using the default settings group.
86
+ #
87
+ # @param key_name [String] the name of the key whose value is to be written
88
+ # @param key_value [String] the data item value of the key specified
89
+ def set key_name, key_value
90
+ raise ArgumentError, "Cannot set a Nil section name." if @section_to_use.nil?
91
+ write @section_to_use, key_name, key_value
92
+ end
93
+
94
+
95
+ # Stash the setting directive and its value into the configuration file
96
+ # using the default settings group.
97
+ #
98
+ # @param key_name [String] the name of the key whose value is to be written
99
+ # @return [String]
100
+ # return the value of the configuration directive in the default group
101
+ def get key_name
102
+ raise ArgumentError, "Cannot get from a Nil section name." if @section_to_use.nil?
103
+ read @section_to_use, key_name
104
+ end
105
+
106
+
107
+ # Write the key/value pair in the parameter into this key/value store's
108
+ # base file-system backing INI file.
109
+ #
110
+ # This method assumes the existence of the backing configuration file at
111
+ # the @file_path instance variable that was set during initialization.
112
+ #
113
+ # Observable value is the written key/value pair within the specified
114
+ # section. The alternate flows are
115
+ #
116
+ # - if the section does not exist it is created
117
+ # - if the section and key exist the value is inserted or overwritten
118
+ #
119
+ # @param section_name [String] name grouping the section of config values
120
+ # @param key [String] the key name of config directive to be written into the file
121
+ # @param value [String] value of the config directive to be written into the file
122
+ #
123
+ def write section_name, key, value
124
+
125
+ config_map = IniFile.new( :filename => @file_path, :encoding => 'UTF-8' )
126
+ config_map = IniFile.load( @file_path ) if File.file? @file_path
127
+ config_map[section_name][key] = value
128
+ config_map.write
129
+
130
+ end
131
+
132
+
133
+ # Given the configuration key name and the context name, get the
134
+ # corresponding key value from the configuration file whose path
135
+ # is acquired using the {self#get_filepath} method.
136
+ #
137
+ # @param key_name [String] the key whose value is to be retrieved
138
+ #
139
+ # @return [String] the value configured for the parameter key
140
+ #
141
+ # @raise ArgumentError for any one of a long list of reasons that
142
+ # cause the key value to not be retrieved. This can range from
143
+ # non-existent directories and files, non readable files, incorrect
144
+ # configurations right down to missing keys or even missing values.
145
+ def read section_name, key_name
146
+
147
+ raise ArgumentError.new "No section given." if section_name.nil? || section_name.strip.empty?
148
+ raise ArgumentError.new "No parameter key given." if key_name.nil? || key_name.strip.empty?
149
+ raise ArgumentError.new "No file found at [ #{@file_path} ]" unless File.exists? @file_path
150
+ the_text = File.read @file_path
151
+ raise ArgumentError.new "This file is empty => [ #{@file_path} ]" if the_text.empty?
152
+
153
+ the_data = IniFile.load @file_path
154
+ key_exists = the_data[ section_name ].has_key?( key_name )
155
+ key_err_msg = "Key [#{key_name}] not found in section [#{section_name}]"
156
+ raise ArgumentError, key_err_msg unless key_exists
157
+
158
+ rawvalue = the_data[section_name][key_name]
159
+ key_val_msg = "Nil empty or whitespace value for key [#{section_name}][#{key_name}]"
160
+ nil_empty_or_whitespace = rawvalue.nil? || rawvalue.chomp.strip.empty?
161
+ raise ArgumentError, key_val_msg if nil_empty_or_whitespace
162
+
163
+ return rawvalue.chomp.strip
164
+
165
+ end
166
+
167
+
168
+ # Return true if the settings configuration file contains the specified
169
+ # parameter key within the current section name that has been set via
170
+ # the {use} method.
171
+ #
172
+ # This method does not check the contents (value) of the key. Even if it
173
+ # is an empty string, this method returns true so long as the section
174
+ # exists and the key exists within that.
175
+ #
176
+ # @param key_name [String]
177
+ # does a key with this name exist within the current map section.
178
+ #
179
+ # @return [Boolean]
180
+ # return true if the current section exists and a key with the parameter
181
+ # name exists within it.
182
+ # return false if <b>either</b> the section <b>or</b> the key do not exist.
183
+ #
184
+ # raise [ArgumentError]
185
+ # if the configuration file does not exist or is empty
186
+ # if the paramter key_name is nil, empty or contains only whitespace
187
+ def contains? key_name
188
+
189
+ raise ArgumentError.new "No parameter key given." if key_name.nil? || key_name.strip.empty?
190
+ raise ArgumentError.new "No file found at [ #{@file_path} ]" unless File.exists? @file_path
191
+ the_text = File.read @file_path
192
+ raise ArgumentError.new "This file is empty => [ #{@file_path} ]" if the_text.empty?
193
+
194
+ the_data = IniFile.load @file_path
195
+ return false unless the_data.has_section?( @section_to_use )
196
+ return the_data[ @section_to_use ].has_key?( key_name )
197
+
198
+ end
199
+
200
+
201
+
202
+ # Return true if the settings configuration file contains the specified
203
+ # section name. This method ignores whatever section that may or may not
204
+ # have been pointed to by the use command.
205
+ #
206
+ # @param section_name [String]
207
+ # does a section with this name exist within the file data structure
208
+ #
209
+ # @return [Boolean]
210
+ # return true if a section exists with the specified name
211
+ def has_section? section_name
212
+
213
+ KeyError.not_new( section_name, self )
214
+
215
+ raise ArgumentError.new "No file found at [ #{@file_path} ]" unless File.exists? @file_path
216
+ the_text = File.read @file_path
217
+ raise ArgumentError.new "This file is empty => [ #{@file_path} ]" if the_text.empty?
218
+
219
+ the_data = IniFile.load @file_path
220
+ return the_data.has_section?( section_name )
221
+
222
+ end
223
+
224
+
225
+
226
+ # Get the time stamp that was written to the key-value store at
227
+ # the point it was first initialized and then subsequently written
228
+ # out (serialized) onto the file-system.
229
+ #
230
+ # The time stamp returned marks the first time this key-value store
231
+ # was conceived by a use case actor and subsequently serialized.
232
+ #
233
+ # @return [String]
234
+ # the string time stamp denoting the first time this key-value
235
+ # store was first initialized and then subsequently written out
236
+ # (serialized) onto the file-system.
237
+ def time_stamp
238
+ return get INIT_TIME_STAMP_NAME
239
+ end
240
+
241
+
242
+
243
+ private
244
+
245
+
246
+
247
+ def create_dir_if_necessary
248
+
249
+ config_directory = File.dirname @file_path
250
+ return if (File.exist? config_directory) && (File.directory? config_directory)
251
+ FileUtils.mkdir_p config_directory
252
+
253
+ end
254
+
255
+
256
+ end
257
+
258
+
259
+ end