rconfigurator 0.0.2
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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +0 -0
- data/README +87 -0
- data/Rakefile +6 -0
- data/bin/rconfig +15 -0
- data/configurator.gemspec +26 -0
- data/lib/rconfigurator.rb +89 -0
- data/lib/rconfigurator/configurator.rb +1 -0
- data/lib/rconfigurator/utilities.rb +13 -0
- data/lib/rconfigurator/version.rb +3 -0
- data/spec/rconfigurator/rconfigurator_spec.rb +27 -0
- data/spec/resources/sample.yml +23 -0
- metadata +81 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
File without changes
|
data/README
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
=== Welcome to RConfigurator!
|
2
|
+
|
3
|
+
--- Configuration shouldn't be hard...
|
4
|
+
|
5
|
+
...and loading configuration for your Ruby application has never been easier.
|
6
|
+
|
7
|
+
RConfigurator automatically "hydrates" your application's module constants by walking
|
8
|
+
through a .yml file. If you've got module constants strewn throughout your project,
|
9
|
+
you can use RConfigurator to aggregate these into one place.
|
10
|
+
|
11
|
+
--- Usage
|
12
|
+
|
13
|
+
To get this going, you just have to require 'rconfigurator' and provide use with the
|
14
|
+
name of the project and the location of the configuration file:
|
15
|
+
|
16
|
+
require 'rconfigurator'
|
17
|
+
RConfigurator.configure! "ExampleModule", "/path/to/my/config"
|
18
|
+
|
19
|
+
Configurator will analyze the file and 'inflate' your module constants using the data it finds there. Let's say you've got the following module constants:
|
20
|
+
|
21
|
+
ExampleModule::KEY = 'value'
|
22
|
+
ExampleModule::NUMERIC_DATA = 3.221
|
23
|
+
ExampleModule::SampleModule::SOME_KEY = 'another value'
|
24
|
+
ExampleModule::KEY_SHOULD_BE_MODULE = I::Am::A::Module
|
25
|
+
|
26
|
+
RConfigurator can create these for you (before you've even defined the modules
|
27
|
+
themselves!) if you point it to the following .yml file:
|
28
|
+
|
29
|
+
key: value
|
30
|
+
numeric_data: 3.221
|
31
|
+
sample_module:
|
32
|
+
some_key: another value
|
33
|
+
key_should_be_module: I::Am::A::Module
|
34
|
+
|
35
|
+
|
36
|
+
RConfigurator even handles some common edge cases for you, in particular the case
|
37
|
+
when the value is itself a module. RConfigurator will construct the module context
|
38
|
+
in place just before it needs a reference.
|
39
|
+
|
40
|
+
For a better feel of how this ends up being useful, or perhaps some inspiration,
|
41
|
+
here's an example of part of a real configuration file I am using for another small project:
|
42
|
+
|
43
|
+
version: 0.3.9
|
44
|
+
release: alpha
|
45
|
+
authors: joseph weissman
|
46
|
+
license: artistic license <http://www.perlfoundation.org/artistic_license_2_0>
|
47
|
+
|
48
|
+
# support module config
|
49
|
+
support:
|
50
|
+
logging:
|
51
|
+
use_chainsaw: true
|
52
|
+
chainsaw:
|
53
|
+
hostname: 'localhost'
|
54
|
+
port: 8071
|
55
|
+
|
56
|
+
# graphics subsystem config
|
57
|
+
graphics:
|
58
|
+
default_window_options:
|
59
|
+
fullscreen: true
|
60
|
+
width: 1920
|
61
|
+
height: 1080
|
62
|
+
|
63
|
+
# ...
|
64
|
+
|
65
|
+
|
66
|
+
--- RConfig
|
67
|
+
|
68
|
+
RConfigurator comes with a debugger that will output the statements it will 'eval'. You can
|
69
|
+
invoke this utility as 'rconfig [file1] [file2] ...' assuming you have installed the gem.
|
70
|
+
|
71
|
+
Running rconfig over the first example yaml file gives us the module structure we are expecting:
|
72
|
+
|
73
|
+
module HypotheticalParentModule; module SampleModule; SOME_KEY = "another value"; end; ; end
|
74
|
+
module I; module Am; module A; module Module; end; end; end; end;
|
75
|
+
module HypotheticalParentModule; KEY_SHOULD_BE_MODULE = I::Am::A::Module; ; end
|
76
|
+
module HypotheticalParentModule; KEY = "value"; ; end
|
77
|
+
module HypotheticalParentModule; NUMERIC_DATA = 3.221; ; end
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
--- Problems?
|
82
|
+
|
83
|
+
Please log bug reports and enhancement proposals here, or feel free to email the author/maintainer of RConfigurator, Joseph Weissman, jweissman1986 (at) gmail.com
|
84
|
+
|
85
|
+
--- Conclusion
|
86
|
+
|
87
|
+
So far in practice, I have found that it is definitely convenient to be able to architecturally separate 'tuning' from code. I like that I can instantiate complex module structures just by adding a few lines of YAML.
|
data/Rakefile
ADDED
data/bin/rconfig
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
unless ARGV.count > 0
|
4
|
+
puts "rconfig -- RConfiguration file verify"
|
5
|
+
puts "USAGE: rconfig [file1] [file2] ... "
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'rconfigurator'
|
11
|
+
require 'yaml'
|
12
|
+
|
13
|
+
ARGV.each do |config_file|
|
14
|
+
RConfigurator.configure!("HypotheticalParentModule", config_file, true)
|
15
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'rconfigurator/version'
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "rconfigurator"
|
6
|
+
s.version = RConfigurator::VERSION
|
7
|
+
s.authors = ["Joseph Weissman"]
|
8
|
+
s.email = ["jweissman1986@gmail.com"]
|
9
|
+
s.homepage = ""
|
10
|
+
s.summary = %q{RConfigurator "hydrates" your Ruby application's module constants by walking
|
11
|
+
through a yaml file}
|
12
|
+
s.description = %q{Got constants strewn throughout your project?
|
13
|
+
You can use RConfigurator to aggregate their definitions into one place.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "rconfigurator"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
# specify any dependencies here; for example:
|
23
|
+
# s.add_development_dependency "rspec"
|
24
|
+
# s.add_runtime_dependency "rest-client"
|
25
|
+
# s.add_runtime_dependency "rspec"
|
26
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "rconfigurator/version"
|
2
|
+
require "rconfigurator/utilities"
|
3
|
+
# require "rconfigurator/configurator"
|
4
|
+
|
5
|
+
|
6
|
+
# make a 'binding' to the local scope visible
|
7
|
+
$__global_scope = binding()
|
8
|
+
|
9
|
+
module RConfigurator
|
10
|
+
|
11
|
+
#
|
12
|
+
# Use this configure! method to both create a new configurator AND
|
13
|
+
# launch the configuration process in one go.
|
14
|
+
#
|
15
|
+
def self.configure!(name, file, debug=false)
|
16
|
+
configurator = Configurator.new(name, file)
|
17
|
+
configurator.configure(debug)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# "Hydrate" a Ruby application's module constants from a configuration .yml
|
22
|
+
#
|
23
|
+
class Configurator
|
24
|
+
|
25
|
+
include StringUtilities
|
26
|
+
|
27
|
+
#
|
28
|
+
# Configurator.new takes the name of the project and a configuration file
|
29
|
+
# It does not perform any configuration yet; you must also call configure
|
30
|
+
# if RConfigurator is invoked this way.
|
31
|
+
#
|
32
|
+
def initialize(project_name, config_file, opts={})
|
33
|
+
@project_name = project_name
|
34
|
+
@config_file = config_file
|
35
|
+
@data = YAML::load(File.open(@config_file)).to_hash
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Kicks off our recursive enumeration of the configuration
|
40
|
+
# data and module constant generation business logic.
|
41
|
+
#
|
42
|
+
def configure(debug=false)
|
43
|
+
parse_and_recursively_create_constants!(@data, [], debug)
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# configure application based on an easily-managed .yml file -- use 'eval'
|
48
|
+
# to generate constants based on the structure of the hash we get from the yaml.
|
49
|
+
# most of the business logic for recursively parsing a hash and creating module
|
50
|
+
# constants basically just involves tracking module names properly.
|
51
|
+
#
|
52
|
+
def parse_and_recursively_create_constants!(hash, module_context = [], debug=false)
|
53
|
+
hash.each do |key, value|
|
54
|
+
if value.is_a? Hash
|
55
|
+
module_name = convert_string_to_camel_case(key)
|
56
|
+
context = module_context.dup << module_name
|
57
|
+
parse_and_recursively_create_constants!(hash[key], context, debug)
|
58
|
+
else
|
59
|
+
value_is_a_module = false
|
60
|
+
|
61
|
+
if value.is_a? String
|
62
|
+
if value.include? "::"
|
63
|
+
value_is_a_module = true
|
64
|
+
else
|
65
|
+
value = "\"#{value}\""
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if value_is_a_module
|
70
|
+
# explicitly build out this module (since it doesn't exist) so that we can talk about it
|
71
|
+
expression = value.split('::').map { |module_name| "module #{module_name}; "}.join(' ')
|
72
|
+
value.split('::').count.times { expression << "end; "}
|
73
|
+
eval(expression, $__global_scope)
|
74
|
+
puts(expression) if debug
|
75
|
+
end
|
76
|
+
|
77
|
+
# define the given constant
|
78
|
+
depth = module_context.count
|
79
|
+
expr = module_context.map { |module_name| "module #{module_name}; " }.join(" ")
|
80
|
+
expr << "#{key.upcase} = #{value}; "
|
81
|
+
depth.times { expr << "end; "}
|
82
|
+
expr = "module #{@project_name}; #{expr}; end"
|
83
|
+
eval(expr, $__global_scope)
|
84
|
+
puts(expr) if debug
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# placeholder for gem process, apparently? any, the real logic is in rconfigurator/configurator.rb
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module RConfigurator
|
2
|
+
|
3
|
+
#
|
4
|
+
# takes a string_with_underbars and ConvertsToCamelCase
|
5
|
+
#
|
6
|
+
module StringUtilities
|
7
|
+
def convert_string_to_camel_case(string)
|
8
|
+
new_string = string.gsub(/^[a-z]|_+[a-z]/) { |a| a.upcase }
|
9
|
+
new_string.gsub!('_', '')
|
10
|
+
new_string
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
libs = %w[ lib/ ]
|
2
|
+
libs.each { |lib| $:.unshift lib unless $:.include? lib }
|
3
|
+
|
4
|
+
require 'rconfigurator'
|
5
|
+
|
6
|
+
describe RConfigurator, "performs dynamic Ruby application initialization" do
|
7
|
+
it "parses a yaml configuration file and generates module constants" do
|
8
|
+
# p RConfigurator.methods - Module.methods
|
9
|
+
|
10
|
+
RConfigurator.configure!("ExampleModuleName", "spec/resources/sample.yml")
|
11
|
+
|
12
|
+
# n.b., these values are defined in the config file at spec/resources/sample.yml
|
13
|
+
ExampleModuleName::KEY.should == 'value'
|
14
|
+
end
|
15
|
+
it "should construct numeric constants correctly" do
|
16
|
+
ExampleModuleName::NUMERIC_DATA.should == 3.221
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should handle nested constants" do
|
20
|
+
ExampleModuleName::SampleModule::SOME_KEY.should == 'another value'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should explicitly construct modules if passed as values" do
|
24
|
+
ExampleModuleName::KEY_SHOULD_BE_MODULE.should be_a_kind_of(Module)
|
25
|
+
ExampleModuleName::KEY_SHOULD_BE_MODULE.should == I::Am::A::Module
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
###########################################
|
2
|
+
#
|
3
|
+
# testing config file
|
4
|
+
#
|
5
|
+
#
|
6
|
+
|
7
|
+
key: value
|
8
|
+
numeric_data: 3.221
|
9
|
+
|
10
|
+
sample_module:
|
11
|
+
some_key: another value
|
12
|
+
|
13
|
+
key_should_be_module: I::Am::A::Module
|
14
|
+
|
15
|
+
#
|
16
|
+
# So, RConfigurator.configure! should create
|
17
|
+
#
|
18
|
+
# Sample::KEY = value
|
19
|
+
# Sample::NUMERIC_DATA = 3.221
|
20
|
+
# Sample::SampleModule::SOME_KEY = 'another value'
|
21
|
+
#
|
22
|
+
# ...etc.
|
23
|
+
#
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rconfigurator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Joseph Weissman
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-09-23 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: |-
|
22
|
+
Got constants strewn throughout your project?
|
23
|
+
You can use RConfigurator to aggregate their definitions into one place.
|
24
|
+
email:
|
25
|
+
- jweissman1986@gmail.com
|
26
|
+
executables:
|
27
|
+
- rconfig
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- .gitignore
|
34
|
+
- Gemfile
|
35
|
+
- LICENSE.txt
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- bin/rconfig
|
39
|
+
- configurator.gemspec
|
40
|
+
- lib/rconfigurator.rb
|
41
|
+
- lib/rconfigurator/configurator.rb
|
42
|
+
- lib/rconfigurator/utilities.rb
|
43
|
+
- lib/rconfigurator/version.rb
|
44
|
+
- spec/rconfigurator/rconfigurator_spec.rb
|
45
|
+
- spec/resources/sample.yml
|
46
|
+
homepage: ""
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project: rconfigurator
|
75
|
+
rubygems_version: 1.8.5
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: RConfigurator "hydrates" your Ruby application's module constants by walking through a yaml file
|
79
|
+
test_files:
|
80
|
+
- spec/rconfigurator/rconfigurator_spec.rb
|
81
|
+
- spec/resources/sample.yml
|