configtoolkit 1.2.0 → 2.0.0
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.
- data/FAQ.txt +113 -25
- data/Hash.txt +128 -0
- data/History.txt +45 -2
- data/KeyValue.txt +235 -0
- data/Manifest.txt +66 -4
- data/README.txt +666 -202
- data/Rakefile +3 -5
- data/Ruby.txt +172 -0
- data/YAML.txt +188 -0
- data/examples/hash_example.rb +71 -0
- data/examples/key_value_example.dump.cfg +5 -0
- data/examples/key_value_example.normal1.cfg +20 -0
- data/examples/key_value_example.normal2.cfg +15 -0
- data/examples/key_value_example.rb +72 -0
- data/examples/key_value_example.wacky.cfg +13 -0
- data/examples/load_example.rb +32 -0
- data/examples/load_example.yaml +34 -0
- data/examples/load_group_example.rb +28 -0
- data/examples/load_group_example.yaml +33 -0
- data/examples/machineconfig.rb +77 -0
- data/examples/ruby_example.rb +32 -0
- data/examples/ruby_example.rcfg +52 -0
- data/examples/usage_example.rb +93 -0
- data/examples/yaml_example.dump.yaml +12 -0
- data/examples/yaml_example.rb +48 -0
- data/examples/yaml_example.yaml +59 -0
- data/lib/configtoolkit.rb +1 -1
- data/lib/configtoolkit/baseconfig.rb +522 -418
- data/lib/configtoolkit/hasharrayvisitor.rb +242 -0
- data/lib/configtoolkit/hashreader.rb +41 -0
- data/lib/configtoolkit/hashwriter.rb +45 -0
- data/lib/configtoolkit/keyvalueconfig.rb +105 -0
- data/lib/configtoolkit/keyvaluereader.rb +597 -0
- data/lib/configtoolkit/keyvaluewriter.rb +157 -0
- data/lib/configtoolkit/prettyprintwriter.rb +167 -0
- data/lib/configtoolkit/reader.rb +62 -0
- data/lib/configtoolkit/rubyreader.rb +270 -0
- data/lib/configtoolkit/types.rb +42 -26
- data/lib/configtoolkit/writer.rb +116 -0
- data/lib/configtoolkit/yamlreader.rb +10 -6
- data/lib/configtoolkit/yamlwriter.rb +113 -71
- data/test/bad_array_index.rcfg +1 -0
- data/test/bad_containing_object_assignment.rcfg +2 -0
- data/test/bad_directive.cfg +1 -0
- data/test/bad_include1.cfg +2 -0
- data/test/bad_include2.cfg +3 -0
- data/test/bad_parameter_reference.rcfg +1 -0
- data/test/contained_sample.cfg +10 -0
- data/test/contained_sample.pretty_print +30 -0
- data/test/contained_sample.rcfg +22 -0
- data/test/contained_sample.yaml +22 -21
- data/test/containers.cfg +6 -0
- data/test/exta_string_after_container.cfg +2 -0
- data/test/extra_container_closing.cfg +2 -0
- data/test/extra_string_after_container.cfg +2 -0
- data/test/extra_string_after_nested_container.cfg +1 -0
- data/test/missing_array_closing.cfg +2 -0
- data/test/missing_array_element.cfg +2 -0
- data/test/missing_directive.cfg +1 -0
- data/test/missing_hash_closing.cfg +2 -0
- data/test/missing_hash_element.cfg +2 -0
- data/test/missing_hash_value.cfg +1 -0
- data/test/missing_include_argument.cfg +1 -0
- data/test/missing_key_value_delimiter.cfg +1 -0
- data/test/readerwritertest.rb +28 -7
- data/test/sample.cfg +10 -0
- data/test/sample.pretty_print +30 -0
- data/test/sample.rcfg +26 -0
- data/test/test_baseconfig.rb +152 -38
- data/test/test_hash.rb +82 -0
- data/test/test_keyvalue.rb +185 -0
- data/test/test_prettyprint.rb +28 -0
- data/test/test_ruby.rb +50 -0
- data/test/test_yaml.rb +33 -26
- data/test/wacky_sample1.cfg +16 -0
- data/test/wacky_sample2.cfg +5 -0
- data/test/wacky_sample3.cfg +4 -0
- data/test/wacky_sample4.cfg +1 -0
- metadata +101 -10
- data/lib/configtoolkit/toolkit.rb +0 -20
- data/test/common.rb +0 -5
data/Rakefile
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
|
3
|
-
$LOAD_PATH.unshift("lib")
|
4
|
-
|
5
3
|
require 'rubygems'
|
6
4
|
require 'hoe'
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
Hoe.new('configtoolkit', "2.0.0") do |p|
|
7
|
+
p.extra_deps << ['relative', '>= 1.0.0']
|
8
|
+
p.extra_deps << ['assertions', '>= 1.0.0']
|
11
9
|
p.remote_rdoc_dir = ''
|
12
10
|
p.developer('DesigningPatterns', 'technical.inquiries@designingpatterns.com')
|
13
11
|
end
|
data/Ruby.txt
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
== RUBY CONFIGURATION FILES:
|
2
|
+
What could be better than configuring Ruby programs with Ruby
|
3
|
+
configuration files, harnessing the full power of Ruby for
|
4
|
+
configuration? The ConfigToolkit::RubyReader supports a Ruby
|
5
|
+
configuration file format that allows configurations to leverage the
|
6
|
+
expressiveness of the Ruby language in a way that's more natural than
|
7
|
+
programatically initializing the configuration (via the
|
8
|
+
ConfigToolkit::HashReader, for instance).
|
9
|
+
|
10
|
+
Ruby configuration files essentially are key-value configuration files
|
11
|
+
parsed by the Ruby interpreter; they allow the full Ruby language to
|
12
|
+
be used while building up a configuration. Parameters are specified
|
13
|
+
by +config.param_name+ or +config.containing_object.param_name+. They
|
14
|
+
can be assigned to and, after assignment, used in other expressions.
|
15
|
+
If a name first is referred to with a setter (i.e., +age+ in
|
16
|
+
<code>config.first.second.age = 5</code>), then the name is assumed to
|
17
|
+
be a parameter name. If a name first is referred to with a getter
|
18
|
+
(i.e., +first+ and +second+ in <code>config.first.second.age =
|
19
|
+
5</code>), then the name is assumed to be an object name (either a
|
20
|
+
containing or a nested configuration object). Objects cannot be set
|
21
|
+
(i.e., <code>config.first.second = 2</code> is illegal). Parameter
|
22
|
+
values, once set, can be referenced in later expressions.
|
23
|
+
|
24
|
+
No +RubyWriter+ class is provided, since the strength of the format is
|
25
|
+
supporting dynamic expressions that calculate configuration values,
|
26
|
+
and any configuration file output by a writer only could consist of
|
27
|
+
static expressions.
|
28
|
+
|
29
|
+
== EXAMPLE:
|
30
|
+
This is a Ruby configuration file:
|
31
|
+
======+examples/ruby_example.rcfg+:
|
32
|
+
#
|
33
|
+
# This file contains MachineConfig configurations
|
34
|
+
# (see examples/machineconfig.rb for the configuration's specification).
|
35
|
+
#
|
36
|
+
|
37
|
+
require 'uri'
|
38
|
+
|
39
|
+
config.num_cpus = 32
|
40
|
+
|
41
|
+
#
|
42
|
+
# Note how the members of the nested OSConfig
|
43
|
+
# can be set by first referring to "os" and then to the
|
44
|
+
# desired member (i.e., config.os.name). config.os
|
45
|
+
# also could have been set with a Hash (see below
|
46
|
+
# for an example).
|
47
|
+
#
|
48
|
+
config.os.name = "AIX"
|
49
|
+
config.os.version = 5.3
|
50
|
+
|
51
|
+
config.behind_firewall = false
|
52
|
+
|
53
|
+
#
|
54
|
+
# Notice how the behind_firewall value can be referenced
|
55
|
+
# in the contains_sensitive_data value assignment, since
|
56
|
+
# it was set above.
|
57
|
+
#
|
58
|
+
config.contains_sensitive_data = config.behind_firewall
|
59
|
+
config.addresses = [
|
60
|
+
URI("http://default.designingpatterns.com"),
|
61
|
+
URI("http://apple.designingpatterns.com")
|
62
|
+
]
|
63
|
+
|
64
|
+
#
|
65
|
+
# A trivial example of using a Ruby expression to calculate
|
66
|
+
# a parameter value.
|
67
|
+
#
|
68
|
+
config.production.www.num_cpus = 32 + 16 + 8 + 4 + 2 + 1 + 1
|
69
|
+
|
70
|
+
#
|
71
|
+
# Note that here the nested OSConfig is being set with a Hash (the
|
72
|
+
# configuration above sets the OSConfig parameters individually).
|
73
|
+
#
|
74
|
+
config.production.www.os = {
|
75
|
+
:name => "Solaris",
|
76
|
+
:version => 10.0
|
77
|
+
}
|
78
|
+
|
79
|
+
config.production.www.contains_sensitive_data = true
|
80
|
+
config.production.www.addresses = [
|
81
|
+
URI("http://www.designingpatterns.com"),
|
82
|
+
URI("http://tokyo.designingpatterns.com")
|
83
|
+
]
|
84
|
+
|
85
|
+
This program loads the two configurations in the file:
|
86
|
+
======+examples/ruby_example.rb+:
|
87
|
+
#!/usr/bin/env ruby
|
88
|
+
|
89
|
+
#
|
90
|
+
# These example programs use the 'relative' gem in order to
|
91
|
+
# express paths relative to __FILE__ cleanly, allowing them to be run from
|
92
|
+
# any directory. In particular, they use the require_relative
|
93
|
+
# method to load examples/machineconfig.rb and
|
94
|
+
# File.expand_path_relative_to_caller in order to refer to
|
95
|
+
# configuration files within the examples directory.
|
96
|
+
#
|
97
|
+
require 'rubygems'
|
98
|
+
require 'relative'
|
99
|
+
require_relative 'machineconfig'
|
100
|
+
|
101
|
+
require 'configtoolkit/rubyreader'
|
102
|
+
|
103
|
+
CONFIGURATION_FILE = File.expand_path_relative_to_caller("ruby_example.rcfg")
|
104
|
+
|
105
|
+
#
|
106
|
+
# The first configuration has no containing object name.
|
107
|
+
#
|
108
|
+
reader = ConfigToolkit::RubyReader.new(CONFIGURATION_FILE)
|
109
|
+
first_config = MachineConfig.load(reader)
|
110
|
+
print("The first config:\n#{first_config}\n")
|
111
|
+
|
112
|
+
#
|
113
|
+
# The second configuration has "production.www" as a containing
|
114
|
+
# object name.
|
115
|
+
#
|
116
|
+
reader = ConfigToolkit::RubyReader.new(CONFIGURATION_FILE)
|
117
|
+
second_config = MachineConfig.load(reader, "production.www")
|
118
|
+
print("The second config:\n#{second_config}\n")
|
119
|
+
|
120
|
+
When run, it produces the following output:
|
121
|
+
======The output of <code>examples/ruby_example.rb</code>:
|
122
|
+
The first config:
|
123
|
+
{
|
124
|
+
os : {
|
125
|
+
name : AIX
|
126
|
+
version: 5.3
|
127
|
+
}
|
128
|
+
behind_firewall : false
|
129
|
+
num_cpus : 32
|
130
|
+
addresses : [
|
131
|
+
http://default.designingpatterns.com,
|
132
|
+
http://apple.designingpatterns.com
|
133
|
+
]
|
134
|
+
contains_sensitive_data: false
|
135
|
+
}
|
136
|
+
|
137
|
+
The second config:
|
138
|
+
production.www: {
|
139
|
+
os : {
|
140
|
+
name : Solaris
|
141
|
+
version: 10.0
|
142
|
+
}
|
143
|
+
behind_firewall : true
|
144
|
+
num_cpus : 64
|
145
|
+
addresses : [
|
146
|
+
http://www.designingpatterns.com,
|
147
|
+
http://tokyo.designingpatterns.com
|
148
|
+
]
|
149
|
+
contains_sensitive_data: true
|
150
|
+
}
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
== FUTURE DIRECTIONS:
|
155
|
+
The Ruby configuration language could be improved in several ways. Firstly,
|
156
|
+
it could provide better support for arrays. For instance, the following
|
157
|
+
configuration file is invalid right now:
|
158
|
+
config.array_param[0] = 3
|
159
|
+
In the future, the parser automatically could detect that +array_param+ is
|
160
|
+
an array and allow array elements to be set.
|
161
|
+
|
162
|
+
In addition, the following configuration file also is invalid right now:
|
163
|
+
config.array_param = []
|
164
|
+
config.array_param[0].fixnum_param = 3
|
165
|
+
config.array_param[0].string_param = "hello"
|
166
|
+
That is, array elements could support object notation. Right now, this would
|
167
|
+
have to be written with Hashes:
|
168
|
+
config.array_param = []
|
169
|
+
config.array_param[0] = {:fixnum_param => 3, :string_param => "hello"}
|
170
|
+
|
171
|
+
We would love feedback and suggestions from the community about future
|
172
|
+
directions for this configuration language!
|
data/YAML.txt
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
== YAML CONFIGURATION FILES:
|
2
|
+
YAML is a clean, flexible data representation language that easily can
|
3
|
+
represent complicated configurations. It natively supports simple
|
4
|
+
types (integers, floats, strings, booleans), and, since Ruby supports
|
5
|
+
serialization of objects to YAML, Ruby's YAML library supports
|
6
|
+
representing objects of virtually any type in YAML. Support for YAML
|
7
|
+
is available for many programming languages, making it attractive for
|
8
|
+
configurations that must be read by several different languages.
|
9
|
+
|
10
|
+
The ConfigToolkit::YAMLReader and ConfigToolkit::YAMLWriter allow
|
11
|
+
configurations to be loaded from and dumped to YAML files.
|
12
|
+
|
13
|
+
== EXAMPLE:
|
14
|
+
The parameter values in YAML configuration files can be native YAML
|
15
|
+
types (strings, integers, floats, booleans, etc.) and also can be
|
16
|
+
serialized Ruby classes. The following configuration file
|
17
|
+
demonstrates this:
|
18
|
+
======+examples/yaml_example.yaml+:
|
19
|
+
#
|
20
|
+
# This file contains MachineConfig configurations
|
21
|
+
# (see examples/machineconfig.rb for the configuration's specification).
|
22
|
+
#
|
23
|
+
|
24
|
+
############################################################
|
25
|
+
# First configuration
|
26
|
+
num_cpus: 32
|
27
|
+
os:
|
28
|
+
name: AIX
|
29
|
+
version: 5.3
|
30
|
+
behind_firewall: no
|
31
|
+
contains_sensitive_data: no
|
32
|
+
addresses:
|
33
|
+
- http://default.designingpatterns.com
|
34
|
+
- http://apple.designingpatterns.com
|
35
|
+
############################################################
|
36
|
+
|
37
|
+
production:
|
38
|
+
############################################################
|
39
|
+
# Second configuration (nested in the production.www
|
40
|
+
# containing object). Note that the elements of the
|
41
|
+
# addresses parameter array are expressed
|
42
|
+
# not as strings, as in the first configuration, but rather
|
43
|
+
# as serialized Ruby URI instances. The YAMLReader class
|
44
|
+
# can read both, and the YAMLWriter class can
|
45
|
+
# output values of either only YAML native types or of serialized Ruby
|
46
|
+
# classes.
|
47
|
+
www:
|
48
|
+
contains_sensitive_data: true
|
49
|
+
addresses:
|
50
|
+
- !ruby/object:URI::HTTP
|
51
|
+
fragment:
|
52
|
+
host: www.designingpatterns.com
|
53
|
+
opaque:
|
54
|
+
password:
|
55
|
+
path: ""
|
56
|
+
port: 80
|
57
|
+
query:
|
58
|
+
registry:
|
59
|
+
scheme: http
|
60
|
+
user:
|
61
|
+
- !ruby/object:URI::HTTP
|
62
|
+
fragment:
|
63
|
+
host: tokyo.designingpatterns.com
|
64
|
+
opaque:
|
65
|
+
password:
|
66
|
+
path: ""
|
67
|
+
port: 80
|
68
|
+
query:
|
69
|
+
registry:
|
70
|
+
scheme: http
|
71
|
+
user:
|
72
|
+
os:
|
73
|
+
name: Solaris
|
74
|
+
version: 10.0
|
75
|
+
num_cpus: 64
|
76
|
+
behind_firewall: true
|
77
|
+
############################################################
|
78
|
+
|
79
|
+
The first configuration is written with only native YAML types
|
80
|
+
while the second configuration is written with serialized Ruby URI
|
81
|
+
classes (the +addresses+ parameter). If the YAML file is to be read
|
82
|
+
by multiple languages, then only native YAML types should be used in
|
83
|
+
the file; FAQ.txt discusses how the ConfigToolkit converts YAML
|
84
|
+
strings to some Ruby types (Pathnames, URIs, Symbols, etc.). The following
|
85
|
+
program shows how this example YAML configuration file can be loaded,
|
86
|
+
and how a configuration can be written as a YAML file:
|
87
|
+
======+examples/yaml_example.rb+:
|
88
|
+
#!/usr/bin/env ruby
|
89
|
+
|
90
|
+
#
|
91
|
+
# These example programs use the 'relative' gem in order to
|
92
|
+
# express paths relative to __FILE__ cleanly, allowing them to be run from
|
93
|
+
# any directory. In particular, they use the require_relative
|
94
|
+
# method to load examples/machineconfig.rb and
|
95
|
+
# File.expand_path_relative_to_caller in order to refer to
|
96
|
+
# configuration files within the examples directory.
|
97
|
+
#
|
98
|
+
require 'rubygems'
|
99
|
+
require 'relative'
|
100
|
+
require_relative 'machineconfig'
|
101
|
+
|
102
|
+
require 'configtoolkit/yamlreader'
|
103
|
+
require 'configtoolkit/yamlwriter'
|
104
|
+
|
105
|
+
CONFIGURATION_FILE = File.expand_path_relative_to_caller("yaml_example.yaml")
|
106
|
+
|
107
|
+
#
|
108
|
+
# The first configuration has no containing object name.
|
109
|
+
#
|
110
|
+
reader = ConfigToolkit::YAMLReader.new(CONFIGURATION_FILE)
|
111
|
+
first_config = MachineConfig.load(reader)
|
112
|
+
print("The first config:\n#{first_config}\n")
|
113
|
+
|
114
|
+
#
|
115
|
+
# The second configuration has "production.www" as a containing
|
116
|
+
# object name. Note that the second configuration
|
117
|
+
# reprents the URI elements of the addresses parameter array
|
118
|
+
# as Ruby URI classes, leveraging Ruby's ability to unserialize
|
119
|
+
# objects from YAML.
|
120
|
+
#
|
121
|
+
reader = ConfigToolkit::YAMLReader.new(CONFIGURATION_FILE)
|
122
|
+
second_config = MachineConfig.load(reader, "production.www")
|
123
|
+
print("The second config:\n#{second_config}\n")
|
124
|
+
|
125
|
+
#
|
126
|
+
# Write second_config to a string stream, which then is written to
|
127
|
+
# stdout. Pass true as the second argument to new in order to specify that
|
128
|
+
# the writer only should write native YAML types (Strings, integers, floats,
|
129
|
+
# booleans, etc.).
|
130
|
+
#
|
131
|
+
string_stream = StringIO.new()
|
132
|
+
writer = ConfigToolkit::YAMLWriter.new(string_stream, true)
|
133
|
+
second_config.dump(writer)
|
134
|
+
print("The second configuration written in YAML with native YAML types:\n")
|
135
|
+
print("#{string_stream.string}")
|
136
|
+
|
137
|
+
Note that the ConfigToolkit::YAMLWriter can dump parameter values with only
|
138
|
+
native YAML types or with serialized Ruby classes, depending on the second
|
139
|
+
argument passed to the ConfigToolkit::YAMLWriter.new method. If a
|
140
|
+
ConfigToolkit::YAMLWriter is instructed to use only native YAML types to
|
141
|
+
express parameter values, it will use the +to_s+ method to convert all
|
142
|
+
parameter values that are not of a native YAML type to strings. When run, the
|
143
|
+
program produces:
|
144
|
+
======The output of <code>examples/yaml_example.rb</code>:
|
145
|
+
The first config:
|
146
|
+
{
|
147
|
+
num_cpus : 32
|
148
|
+
addresses : [
|
149
|
+
http://default.designingpatterns.com,
|
150
|
+
http://apple.designingpatterns.com
|
151
|
+
]
|
152
|
+
contains_sensitive_data: false
|
153
|
+
os : {
|
154
|
+
version: 5.3
|
155
|
+
name : AIX
|
156
|
+
}
|
157
|
+
behind_firewall : false
|
158
|
+
}
|
159
|
+
|
160
|
+
The second config:
|
161
|
+
production.www: {
|
162
|
+
num_cpus : 64
|
163
|
+
addresses : [
|
164
|
+
http://www.designingpatterns.com,
|
165
|
+
http://tokyo.designingpatterns.com
|
166
|
+
]
|
167
|
+
contains_sensitive_data: true
|
168
|
+
os : {
|
169
|
+
version: 10.0
|
170
|
+
name : Solaris
|
171
|
+
}
|
172
|
+
behind_firewall : true
|
173
|
+
}
|
174
|
+
|
175
|
+
The second configuration written in YAML with native YAML types:
|
176
|
+
---
|
177
|
+
production:
|
178
|
+
www:
|
179
|
+
addresses:
|
180
|
+
- http://www.designingpatterns.com
|
181
|
+
- http://tokyo.designingpatterns.com
|
182
|
+
os:
|
183
|
+
name: Solaris
|
184
|
+
version: 10.0
|
185
|
+
behind_firewall: true
|
186
|
+
num_cpus: 64
|
187
|
+
contains_sensitive_data: true
|
188
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# These example programs use the 'relative' gem in order to
|
5
|
+
# express paths relative to __FILE__ cleanly, allowing them to be run from
|
6
|
+
# any directory. In particular, they use the require_relative
|
7
|
+
# method to load examples/machineconfig.rb and
|
8
|
+
# File.expand_path_relative_to_caller in order to refer to
|
9
|
+
# configuration files within the examples directory.
|
10
|
+
#
|
11
|
+
require 'rubygems'
|
12
|
+
require 'relative'
|
13
|
+
require_relative 'machineconfig'
|
14
|
+
|
15
|
+
require 'configtoolkit/hashreader'
|
16
|
+
require 'configtoolkit/hashwriter'
|
17
|
+
|
18
|
+
#
|
19
|
+
# The first configuration has no containing object name.
|
20
|
+
#
|
21
|
+
config_hash = {
|
22
|
+
:num_cpus => 32,
|
23
|
+
:os => {
|
24
|
+
:name => "AIX",
|
25
|
+
:version => 5.3
|
26
|
+
},
|
27
|
+
:behind_firewall => false,
|
28
|
+
:contains_sensitive_data => false,
|
29
|
+
:addresses => [
|
30
|
+
URI("http://default.designingpatterns.com"),
|
31
|
+
URI("http://apple.designingpatterns.com")
|
32
|
+
]
|
33
|
+
}
|
34
|
+
reader = ConfigToolkit::HashReader.new(config_hash)
|
35
|
+
first_config = MachineConfig.load(reader)
|
36
|
+
print("The first config:\n#{first_config}\n")
|
37
|
+
|
38
|
+
#
|
39
|
+
# The second configuration has "production.www" as a containing
|
40
|
+
# object name and therefore the configuration is mapped to by
|
41
|
+
# :www in a Hash, which in turn is mapped to by :production
|
42
|
+
# in a containing Hash.
|
43
|
+
#
|
44
|
+
config_hash = {
|
45
|
+
:production => {
|
46
|
+
:www => {
|
47
|
+
:num_cpus => 64,
|
48
|
+
:os => {
|
49
|
+
:name => "Solaris",
|
50
|
+
:version => 10.0
|
51
|
+
},
|
52
|
+
:contains_sensitive_data => true,
|
53
|
+
:addresses => [
|
54
|
+
URI("http://www.designingpatterns.com"),
|
55
|
+
URI("http://tokyo.designingpatterns.com")
|
56
|
+
]
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
reader = ConfigToolkit::HashReader.new(config_hash)
|
61
|
+
second_config = MachineConfig.load(reader, "production.www")
|
62
|
+
print("The second config:\n#{second_config}\n")
|
63
|
+
|
64
|
+
#
|
65
|
+
# After the call to dump, the config_hash instance member of the HashWriter
|
66
|
+
# instance contains the Hash representation of second_config.
|
67
|
+
#
|
68
|
+
writer = ConfigToolkit::HashWriter.new()
|
69
|
+
second_config.dump(writer)
|
70
|
+
print("The Hash dumped from the second config:\n")
|
71
|
+
print("#{writer.config_hash.inspect}\n")
|