safedb 0.01.0001
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.yardopts +3 -0
- data/Gemfile +10 -0
- data/LICENSE +21 -0
- data/README.md +793 -0
- data/Rakefile +16 -0
- data/bin/safe +5 -0
- data/lib/configs/README.md +58 -0
- data/lib/extension/array.rb +162 -0
- data/lib/extension/dir.rb +35 -0
- data/lib/extension/file.rb +123 -0
- data/lib/extension/hash.rb +33 -0
- data/lib/extension/string.rb +572 -0
- data/lib/factbase/facts.safedb.net.ini +38 -0
- data/lib/interprete.rb +462 -0
- data/lib/keytools/PRODUCE_RAND_SEQ_USING_DEV_URANDOM.txt +0 -0
- data/lib/keytools/kdf.api.rb +243 -0
- data/lib/keytools/kdf.bcrypt.rb +265 -0
- data/lib/keytools/kdf.pbkdf2.rb +262 -0
- data/lib/keytools/kdf.scrypt.rb +190 -0
- data/lib/keytools/key.64.rb +326 -0
- data/lib/keytools/key.algo.rb +109 -0
- data/lib/keytools/key.api.rb +1391 -0
- data/lib/keytools/key.db.rb +330 -0
- data/lib/keytools/key.docs.rb +195 -0
- data/lib/keytools/key.error.rb +110 -0
- data/lib/keytools/key.id.rb +271 -0
- data/lib/keytools/key.ident.rb +243 -0
- data/lib/keytools/key.iv.rb +107 -0
- data/lib/keytools/key.local.rb +259 -0
- data/lib/keytools/key.now.rb +402 -0
- data/lib/keytools/key.pair.rb +259 -0
- data/lib/keytools/key.pass.rb +120 -0
- data/lib/keytools/key.rb +585 -0
- data/lib/logging/gem.logging.rb +132 -0
- data/lib/modules/README.md +43 -0
- data/lib/modules/cryptology/aes-256.rb +154 -0
- data/lib/modules/cryptology/amalgam.rb +70 -0
- data/lib/modules/cryptology/blowfish.rb +130 -0
- data/lib/modules/cryptology/cipher.rb +207 -0
- data/lib/modules/cryptology/collect.rb +138 -0
- data/lib/modules/cryptology/crypt.io.rb +225 -0
- data/lib/modules/cryptology/engineer.rb +99 -0
- data/lib/modules/mappers/dictionary.rb +288 -0
- data/lib/modules/storage/coldstore.rb +186 -0
- data/lib/modules/storage/git.store.rb +399 -0
- data/lib/session/fact.finder.rb +334 -0
- data/lib/session/require.gem.rb +112 -0
- data/lib/session/time.stamp.rb +340 -0
- data/lib/session/user.home.rb +49 -0
- data/lib/usecase/cmd.rb +487 -0
- data/lib/usecase/config/README.md +57 -0
- data/lib/usecase/docker/README.md +146 -0
- data/lib/usecase/docker/docker.rb +49 -0
- data/lib/usecase/edit/README.md +43 -0
- data/lib/usecase/edit/delete.rb +46 -0
- data/lib/usecase/export.rb +40 -0
- data/lib/usecase/files/README.md +37 -0
- data/lib/usecase/files/eject.rb +56 -0
- data/lib/usecase/files/file_me.rb +78 -0
- data/lib/usecase/files/read.rb +169 -0
- data/lib/usecase/files/write.rb +89 -0
- data/lib/usecase/goto.rb +57 -0
- data/lib/usecase/id.rb +36 -0
- data/lib/usecase/import.rb +157 -0
- data/lib/usecase/init.rb +63 -0
- data/lib/usecase/jenkins/README.md +146 -0
- data/lib/usecase/jenkins/jenkins.rb +208 -0
- data/lib/usecase/login.rb +71 -0
- data/lib/usecase/logout.rb +28 -0
- data/lib/usecase/open.rb +71 -0
- data/lib/usecase/print.rb +40 -0
- data/lib/usecase/put.rb +81 -0
- data/lib/usecase/set.rb +44 -0
- data/lib/usecase/show.rb +138 -0
- data/lib/usecase/terraform/README.md +91 -0
- data/lib/usecase/terraform/terraform.rb +121 -0
- data/lib/usecase/token.rb +35 -0
- data/lib/usecase/update/README.md +55 -0
- data/lib/usecase/update/rename.rb +180 -0
- data/lib/usecase/use.rb +41 -0
- data/lib/usecase/verse.rb +20 -0
- data/lib/usecase/view.rb +71 -0
- data/lib/usecase/vpn/README.md +150 -0
- data/lib/usecase/vpn/vpn.ini +31 -0
- data/lib/usecase/vpn/vpn.rb +54 -0
- data/lib/version.rb +3 -0
- data/safedb.gemspec +34 -0
- metadata +193 -0
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
# -
|
5
|
+
# - This configuration allows us to run "rake test"
|
6
|
+
# - and invoke minitest to execute all files in the
|
7
|
+
# - test directory with names ending in "_test.rb".
|
8
|
+
# -
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << "test"
|
11
|
+
t.libs << "lib"
|
12
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
13
|
+
end
|
14
|
+
|
15
|
+
task :default => :test
|
16
|
+
|
data/bin/safe
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
# Modifying Safe's Behaviour | 4 Configuration Scopes
|
3
|
+
|
4
|
+
Safe's behaviour can (by default) be modified in a manner that is scoped in 4 ways. Configuration directives can alter behaviour within
|
5
|
+
|
6
|
+
1. a **book global** scope
|
7
|
+
2. a **machine local** scope
|
8
|
+
3. a **shell session** scope and
|
9
|
+
4. a **machine global** scope
|
10
|
+
|
11
|
+
The scoping concept is similar to Git's --local and --global but it works in a different way.
|
12
|
+
|
13
|
+
|
14
|
+
## 1. Book Global Scope
|
15
|
+
|
16
|
+
Directives issued against a safe book **"feel local"** but are global in that the behaviour persists on every machine that works with the book.
|
17
|
+
|
18
|
+
Git's --local is different because cloning the repository on another machine wipe's out the directives. With safe the directives continue to alter behaviour even when the book is cloned and/or used on another machine.
|
19
|
+
|
20
|
+
|
21
|
+
## 2. Machine Local Scope
|
22
|
+
|
23
|
+
This is similar to Git's --global directive which affects all repositories owned by a user on a given machine.
|
24
|
+
|
25
|
+
Directives with a machine local scope **can influence the behaviour** of every Safe book one logs into on a machine. Move to another machine and the behaviour becomes unstuck.
|
26
|
+
|
27
|
+
== Configuration Directive Precedence
|
28
|
+
|
29
|
+
Note the sentence **can influence behaviour** as opposed to **will influence behaviour**.
|
30
|
+
|
31
|
+
If a directive with a book global scope says "Yes" and the same directive exists but says "No" with machine local scope the "Yes" wins out.
|
32
|
+
|
33
|
+
A book global directive overrides its machine local twin.
|
34
|
+
|
35
|
+
|
36
|
+
## 3. Shell Session Scope
|
37
|
+
|
38
|
+
The self explanatory **shell session scoped** directives override their siblings be they book global or machine local.
|
39
|
+
|
40
|
+
Alas, their elevated privileges are countered by relatively short lifespans. Shell session directives only last until either a logout is issued or the shell session comes to an end.
|
41
|
+
|
42
|
+
|
43
|
+
## 4. Default | Machine Global Scope
|
44
|
+
|
45
|
+
Did you notice only **one (1) user** is affected by directives with a machine local scope as long as it isn't overriden.
|
46
|
+
|
47
|
+
Directives with a **machine global scope** are the **default** and are set during an install or upgrade.
|
48
|
+
|
49
|
+
They can potentially affect **every user and every safe book**. Even though their longevity is undisputed, their precedence is the lowest when going head to head with their 3 siblings.
|
50
|
+
|
51
|
+
## The Naked Eye
|
52
|
+
|
53
|
+
Directives with a book global scope **aren't visible to the naked eye**. They are encrypted within the master safe database and thus protected from prying eyes.
|
54
|
+
|
55
|
+
The other 3 directive types exist in plain text
|
56
|
+
|
57
|
+
- either where the gem is **installed** (machine global scope)
|
58
|
+
- or in the INI file in **.safe** off the user's home directory
|
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# Reopen the core ruby Array class and add the below methods to it.
|
5
|
+
#
|
6
|
+
# Case Sensitivity rules for [ALL] the below methods that are
|
7
|
+
# added to the core Ruby string class.
|
8
|
+
#
|
9
|
+
# For case insensitive behaviour make sure you downcase both the
|
10
|
+
# string object and the parameter strings (or strings within
|
11
|
+
# other parameter objects, like arrays and hashes).
|
12
|
+
class Array
|
13
|
+
|
14
|
+
|
15
|
+
# The returned string is a result of a union (join) of all the
|
16
|
+
# (expected) string array elements followed by the <b>deletion</b>
|
17
|
+
# of <b>all <em>non</em> alphanumeric characters</b>.
|
18
|
+
#
|
19
|
+
# <b>Disambiguating the String for Cross Platform Use</b>
|
20
|
+
#
|
21
|
+
# This behaviour is typically used for transforming text that is
|
22
|
+
# about to be signed or digested (hashed). Removing all the non
|
23
|
+
# alpha-numeric characters disambiguates the string.
|
24
|
+
#
|
25
|
+
# An example is the exclusion of line ending characters which in
|
26
|
+
# Windows are different from Linux.
|
27
|
+
#
|
28
|
+
# This disambiguation means that signing functions will return the
|
29
|
+
# same result on widely variant platfoms like Windows vs CoreOS.
|
30
|
+
#
|
31
|
+
# @return [String]
|
32
|
+
# Returns the alphanumeric union of the strings within this array.
|
33
|
+
#
|
34
|
+
# @raise [ArgumentError]
|
35
|
+
# if the array is nil or empty. Also an error will be thrown if
|
36
|
+
# the array contains objects that cannot be naturally converted
|
37
|
+
# to a string.
|
38
|
+
def alphanumeric_union
|
39
|
+
raise ArgumentError, "Cannot do alphanumeric union on an empty array." if self.empty?
|
40
|
+
return self.join.to_alphanumeric
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Log the array using our logging mixin by printing every array
|
45
|
+
# item into its own log line. In most cases we (the array) are
|
46
|
+
# a list of strings, however if not, each item's to_string method
|
47
|
+
# is invoked and the result printed using one log line.
|
48
|
+
#
|
49
|
+
# The INFO log level is used to log the lines - if this is not
|
50
|
+
# appropriate create a (level) parameterized log lines method.
|
51
|
+
def log_lines
|
52
|
+
|
53
|
+
self.each do |line|
|
54
|
+
clean_line = line.to_s.chomp.gsub("\\n","")
|
55
|
+
log.info(x) { line } if clean_line.length > 0
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Get the text [in between] this and that delimeter [exclusively].
|
62
|
+
# Exclusively means the returned text [does not] include either of
|
63
|
+
# the matched delimeters (although an unmatched instance of [this]
|
64
|
+
# delimeter may appear in the in-between text).
|
65
|
+
#
|
66
|
+
# --------------------
|
67
|
+
# Multiple Delimiters
|
68
|
+
# --------------------
|
69
|
+
#
|
70
|
+
# When multiple delimiters exist, the text returned is in between the
|
71
|
+
#
|
72
|
+
# [a] - first occurrence of [this] delimeter AND the
|
73
|
+
# [b] - 1st occurrence of [that] delimeter [AFTER] the 1st delimiter
|
74
|
+
#
|
75
|
+
# Instances of [that] delimiter occurring before [this] are ignored.
|
76
|
+
# The text could contain [this] delimeter instances but is guaranteed
|
77
|
+
# not to contain a [that] delimeter.
|
78
|
+
#
|
79
|
+
# -----------
|
80
|
+
# Parameters
|
81
|
+
# -----------
|
82
|
+
#
|
83
|
+
# this_delimiter : begin delimeter (not included in returned string)
|
84
|
+
# that_delimiter : end delimeter (not included in returned string)
|
85
|
+
#
|
86
|
+
# -----------
|
87
|
+
# Exceptions
|
88
|
+
# -----------
|
89
|
+
#
|
90
|
+
# An exception (error) will be thrown if
|
91
|
+
#
|
92
|
+
# => any nil (or empties) exist in the input parameters
|
93
|
+
# => [this] delimeter does not appear in the in_string
|
94
|
+
# => [that] delimeter does not appear after [this] one
|
95
|
+
#
|
96
|
+
def before_and_after begin_delimeter, end_delimeter
|
97
|
+
|
98
|
+
Throw.if_nil_or_empty_strings [ self, begin_delimeter, end_delimeter ]
|
99
|
+
|
100
|
+
before_after_lines = []
|
101
|
+
in_middle_bit = false
|
102
|
+
|
103
|
+
self.each do |candidate_line|
|
104
|
+
|
105
|
+
is_middle_boundary = !in_middle_bit && candidate_line.downcase.include?(begin_delimeter.downcase)
|
106
|
+
if is_middle_boundary
|
107
|
+
in_middle_bit = true
|
108
|
+
next
|
109
|
+
end
|
110
|
+
|
111
|
+
unless in_middle_bit
|
112
|
+
before_after_lines.push candidate_line
|
113
|
+
next
|
114
|
+
end
|
115
|
+
|
116
|
+
#--
|
117
|
+
#-- Now we are definitely in the middle bit.
|
118
|
+
#-- Let's check for the middle end delimeter
|
119
|
+
#--
|
120
|
+
if candidate_line.downcase.include? end_delimeter.downcase
|
121
|
+
in_middle_bit = false
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
return before_after_lines
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def middlle_bit begin_delimeter, end_delimeter
|
132
|
+
|
133
|
+
Throw.if_nil_or_empty_strings [ self, begin_delimeter, end_delimeter ]
|
134
|
+
|
135
|
+
middle_lines = []
|
136
|
+
in_middle_bit = false
|
137
|
+
|
138
|
+
self.each do |candidate_line|
|
139
|
+
|
140
|
+
is_middle_boundary = !in_middle_bit && candidate_line.downcase.include?(begin_delimeter.downcase)
|
141
|
+
if is_middle_boundary
|
142
|
+
in_middle_bit = true
|
143
|
+
next
|
144
|
+
end
|
145
|
+
|
146
|
+
end_of_middle = in_middle_bit && candidate_line.downcase.include?(end_delimeter.downcase)
|
147
|
+
return middle_lines if end_of_middle
|
148
|
+
|
149
|
+
#--
|
150
|
+
#-- We are definitely in the middle bit.
|
151
|
+
#--
|
152
|
+
middle_lines.push(candidate_line) if in_middle_bit
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
unreachable_str = "This point should be unreachable unless facts are ended."
|
157
|
+
raise RuntimeError.new unreachable_str
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# --
|
4
|
+
# -- Reopen the core ruby Dirctory class and add the below methods to it.
|
5
|
+
# --
|
6
|
+
class Dir
|
7
|
+
|
8
|
+
# --
|
9
|
+
# -- Put all the files starting with the given string in
|
10
|
+
# -- alphabetical ascending order and then return the file
|
11
|
+
# -- that comes last.
|
12
|
+
# --
|
13
|
+
# -- Throw an exception if no file in this folder starts
|
14
|
+
# -- with the given string
|
15
|
+
# --
|
16
|
+
def ascii_order_file_starting_with starts_with_string
|
17
|
+
|
18
|
+
recently_added_file = nil
|
19
|
+
filepath_leadstr = File.join self.path, starts_with_string
|
20
|
+
Dir.glob("#{filepath_leadstr}*").sort.each do |candidate_file|
|
21
|
+
|
22
|
+
next if File.directory? candidate_file
|
23
|
+
recently_added_file = candidate_file
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
Throw.if_nil recently_added_file
|
28
|
+
Throw.if_not_exists recently_added_file
|
29
|
+
return recently_added_file
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Reopen the core ruby File class and add the below methods to it.
|
4
|
+
class File
|
5
|
+
|
6
|
+
# Get the full filepath of a sister file that potentially lives
|
7
|
+
# in the same directory that the leaf class is executing from and
|
8
|
+
# has the same name as the leaf class but a different extension.
|
9
|
+
#
|
10
|
+
# == Usage
|
11
|
+
#
|
12
|
+
# If class OpenFoo:Bar extends class OpenFoo:Baz and we are looking
|
13
|
+
# for an INI file in the folder that OpenFoo:Bar lives in we can
|
14
|
+
# call this method within OpenFoo:Baz like this.
|
15
|
+
#
|
16
|
+
# ini_filepath = sister_filepath( "ini", :execute )
|
17
|
+
# # => /var/lib/gems/2.5.0/gems/fooey-0.2.99/lib/barry/bazzy/bar.ini
|
18
|
+
#
|
19
|
+
# == Common Implementation
|
20
|
+
#
|
21
|
+
# Object orientation scuppers the commonly used technique which
|
22
|
+
# derives the path from __FILE__
|
23
|
+
#
|
24
|
+
# class_directory = File.dirname( __FILE__ )
|
25
|
+
# leaf_class_name = self.class.name.split(":").last.downcase
|
26
|
+
# sister_filepath = File.join ( class_directory, "#{leaf_class_name}.#{extension}" )
|
27
|
+
#
|
28
|
+
# With object orientation - running the above code within the
|
29
|
+
# abstracted (parent) class would produce a resultant filepath
|
30
|
+
# based on the folder the parent class is in rather than the
|
31
|
+
# extended "concrete" class.
|
32
|
+
#
|
33
|
+
# == Value Proposition
|
34
|
+
#
|
35
|
+
# You can call this method from the parent (abstract) class and it
|
36
|
+
# will still correctly return the path to the potential sister file
|
37
|
+
# living in the directory that the leaf class sits in.
|
38
|
+
#
|
39
|
+
# Put differently - this extension method allows code executing in
|
40
|
+
# the parent class to correctly pinpoint a file in the directory of
|
41
|
+
# the leaf class be it in the same or a different folder.
|
42
|
+
#
|
43
|
+
# @param caller
|
44
|
+
# the calling class object usually passed in using <tt>self</tt>
|
45
|
+
#
|
46
|
+
# @param extension
|
47
|
+
# the extension of a sister file that carries the same simple
|
48
|
+
# (downcased) name of the leaf class of this method's caller.
|
49
|
+
#
|
50
|
+
# Omit the (segregating) period character when providing this
|
51
|
+
# extension parameter.
|
52
|
+
#
|
53
|
+
# @param method_symbol
|
54
|
+
# the method name in symbolic form of any method defined in
|
55
|
+
# the leaf class even if the method overrides one of the same
|
56
|
+
# name in the parent class.
|
57
|
+
#
|
58
|
+
# @return the filepath of a potential sister file living in the same
|
59
|
+
# directory as the class, bearing the same (downcased) name
|
60
|
+
# as the class with the specified extension.
|
61
|
+
def self.sister_filepath caller, extension, method_symbol
|
62
|
+
|
63
|
+
leaf_classname = caller.class.name.split(":").last.downcase
|
64
|
+
execute_method = caller.method( method_symbol )
|
65
|
+
leaf_classpath = execute_method.source_location.first
|
66
|
+
leaf_directory = File.dirname( leaf_classpath )
|
67
|
+
lower_filename = "#{leaf_classname}.#{extension}"
|
68
|
+
return File.join( leaf_directory, lower_filename )
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# This method adds (logging its own contents) behaviour to
|
74
|
+
# the standard library {File} class. If this File points to
|
75
|
+
# a directory - that folder's single level content files are
|
76
|
+
# listed inside the logs.
|
77
|
+
#
|
78
|
+
# The <tt>DEBUG</tt> log level is used for logging. To change this
|
79
|
+
# create a new parameterized method.
|
80
|
+
#
|
81
|
+
# @param file_context [String] context denotes the whys and wherefores of this file.
|
82
|
+
def log_contents file_context
|
83
|
+
|
84
|
+
## This will fail - add physical raise statement.
|
85
|
+
Throw.if_not_exists self
|
86
|
+
|
87
|
+
log.debug(x) { "# -- ------------------------------------------------------------------------ #" }
|
88
|
+
log.debug(x) { "# -- ------------------------------------------------------------------------ #" }
|
89
|
+
log.debug(x) { "# -- The File Path to Log => #{self}" }
|
90
|
+
|
91
|
+
hr_file_size = PrettyPrint.byte_size( File.size(self) )
|
92
|
+
dotless_extension = File.extname( self )[1..-1]
|
93
|
+
parent_dir_name = File.basename( File.dirname( self ) )
|
94
|
+
file_name = File.basename self
|
95
|
+
is_zip = dotless_extension.eql? "zip"
|
96
|
+
|
97
|
+
log.debug(x) { "# -- ------------------------------------------------------------------------ #" }
|
98
|
+
log.debug(x) { "# -- File Name => #{file_name}" }
|
99
|
+
log.debug(x) { "# -- File Size => #{hr_file_size}" }
|
100
|
+
log.debug(x) { "# -- File Type => #{file_context}" }
|
101
|
+
log.debug(x) { "# -- In Folder => #{parent_dir_name}" }
|
102
|
+
log.debug(x) { "# -- ------------------------------------------------------------------------ #" }
|
103
|
+
|
104
|
+
log.debug(x) { "File #{file_name} is a zip (binary) file." } if is_zip
|
105
|
+
return if is_zip
|
106
|
+
|
107
|
+
File.open( self, "r") do | file_obj |
|
108
|
+
line_no = 1
|
109
|
+
file_obj.each_line do | file_line |
|
110
|
+
line_num = sprintf '%03d', line_no
|
111
|
+
clean_line = file_line.chomp.strip
|
112
|
+
log.debug(x) { "# -- [#{line_num}] - #{clean_line}" }
|
113
|
+
line_no += 1
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
log.debug(x) { "# -- ------------------------------------------------------------------------ #" }
|
118
|
+
log.debug(x) { "# -- [#{file_context}] End of File [ #{File.basename(self)} ]" }
|
119
|
+
log.debug(x) { "# -- ------------------------------------------------------------------------ #" }
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Reopen the core ruby Hash class and add the below methods to it.
|
4
|
+
class Hash
|
5
|
+
|
6
|
+
# This method adds (logging its own contents) behaviour to
|
7
|
+
# the standard library {Hash} class.
|
8
|
+
#
|
9
|
+
# @note This behaviour does not consider that SECRETS may be inside
|
10
|
+
# the key value maps - it logs itself without a care in the world.
|
11
|
+
# This functionality must be included if this behaviourr is used by
|
12
|
+
# any cryptography classes.
|
13
|
+
#
|
14
|
+
# The <tt>DEBUG</tt> log level is used for logging. To change this
|
15
|
+
# create a new parameterized method.
|
16
|
+
def log_contents
|
17
|
+
|
18
|
+
log.debug(x) { "# --- ----------------------------------------------" }
|
19
|
+
log.debug(x) { "# --- Map has [#{self.length}] key/value pairs." }
|
20
|
+
log.debug(x) { "# --- ----------------------------------------------" }
|
21
|
+
|
22
|
+
self.each do |the_key, the_value|
|
23
|
+
|
24
|
+
padded_key = sprintf '%-33s', the_key
|
25
|
+
log.debug(x) { "# --- #{padded_key} => #{the_value}" }
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
log.debug(x) { "# --- ----------------------------------------------" }
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|