natehop-fig 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Nathan Hopkins
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,13 @@
1
+ =Fig
2
+
3
+ ==Just made some significant changes. I will be upating the docs and tutorial videos soon.
4
+
5
+ DRY up those magic numbers and hard coded strings into something more managable.
6
+ Fig is the smart way to manage the stuff that really belongs in a config file... not scattered around your codebase.
7
+
8
+ Click here http://www.screencast.com/t/I8ezeJ9Txg to view a quick screencast that demonstrates how to use Fig.
9
+
10
+ More documentation coming soon...
11
+
12
+
13
+ Copyright (c) 2008 Nathan Hopkins, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'echoe'
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Test the fig plugin.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'lib'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the fig plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Fig'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README.rdoc')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ Echoe.new('fig', '0.8.0') do |p|
26
+ p.description = "The smart way to manage configuration settings for your Ruby applications."
27
+ p.url = "http://github.com/natehop/fig"
28
+ p.author = "Nathan Hopkins"
29
+ p.email = "natehop@gmail.com"
30
+ p.ignore_pattern = ["nbproject*"]
31
+ p.development_dependencies = []
32
+ puts p.class
33
+ end
34
+
35
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each {|file| load file}
data/fig.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{fig}
5
+ s.version = "0.8.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Nathan Hopkins"]
9
+ s.date = %q{2009-03-14}
10
+ s.description = %q{The smart way to manage configuration settings for your Ruby applications.}
11
+ s.email = %q{natehop@gmail.com}
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/fig.rb", "lib/string.rb", "tasks/fig_tasks.rake"]
13
+ s.files = ["README.rdoc", "install.rb", "MIT-LICENSE", "test/test.yml", "test/suite.rb", "test/test2.yml", "test/string_test.rb", "test/fig_test.rb", "Manifest", "uninstall.rb", "Rakefile", "init.rb", "lib/fig.rb", "lib/string.rb", "tasks/fig_tasks.rake", "fig.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/natehop/fig}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Fig", "--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{fig}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{The smart way to manage configuration settings for your Ruby applications.}
21
+ s.test_files = ["test/string_test.rb", "test/fig_test.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'string'
2
+ require 'fig'
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
data/lib/fig.rb ADDED
@@ -0,0 +1,107 @@
1
+ require 'yaml'
2
+ require 'ostruct'
3
+ require 'monitor'
4
+
5
+ class Fig
6
+
7
+ # Constructor...
8
+ #
9
+ # ===Params
10
+ # * *file_path* - Path to the config file that should be loaded.
11
+ def initialize(file_path)
12
+ @file_path = file_path
13
+ load
14
+ end
15
+
16
+ # Returns the config file file as a YAML Hash.
17
+ attr_reader :yaml
18
+
19
+
20
+ # Returns an OpenStruct object representation of the config file.
21
+ # This allows you to access config settings with dot notation.
22
+ attr_reader :settings
23
+
24
+ # The safest way to get a config setting.
25
+ # Requesting a non-exsisting key, will simply return a nil value instead of raising an error.
26
+ #
27
+ # Examples:
28
+ # Fig.get_setting('some.nested.setting')
29
+ #
30
+ # ===Params
31
+ # * *key* - A case insensivie config key
32
+ #
33
+ # *Returns* The value of the config setting requested.
34
+ # This may be the value itself or an OpenStruct containing child args
35
+ def get_setting(key)
36
+ setting = settings
37
+ keys = key.to_s.downcase.split(/\./)
38
+
39
+ keys.each do |k|
40
+ item = eval("setting.#{k}")
41
+ return nil unless item
42
+ setting = item
43
+ end
44
+
45
+ setting
46
+ end
47
+
48
+ # Loads the config file and builds the internal Fig objects.
49
+ # Can be used to reload the file when changes have been made.
50
+ def load
51
+ @yaml = YAML.load_file(@file_path)
52
+ @yaml.each {|k, v| interpolate_setting(v)}
53
+ @settings = OpenStruct.new
54
+ add_hash(@settings, @yaml)
55
+ end
56
+
57
+ private
58
+
59
+ # Invoked recursively to implicitly interpolate all settings for the passed value.
60
+ # Config values that contain the pattern /{fig:/ are implicitly interpolated,
61
+ # replacing the "fig" placeholder with the actual value from elsewhere in the config file.
62
+ #
63
+ # Example:
64
+ # name: Nathan Hopkins
65
+ # message: "This is a test! Hello #{fig:example.name}"
66
+ #
67
+ # ===Params
68
+ # * *value* [_Object_] The value to interpolate.
69
+ def interpolate_setting(value)
70
+ if value.is_a?(Hash)
71
+ value.each {|k,v| interpolate_setting(v) }
72
+ elsif value.is_a?(String)
73
+ pattern = /\{fig:/i
74
+ start = value.index(pattern, 0)
75
+ replace = {}
76
+
77
+ while start
78
+ finish = value.index(/\}/, start)
79
+ key = value[(start + 1)..(finish - 1)]
80
+ replace[key] = eval("@yaml['#{key.sub(/^fig:/i, "").gsub(/\./, "']['")}'].to_s")
81
+ start = value.index(pattern, finish)
82
+ end
83
+
84
+ value.interpolate(replace, true)
85
+ end
86
+ end
87
+
88
+ # Recursively adds a hash to an OpenStruct object, ultimately creating a complete OpenStruct object with attributes
89
+ # for all key/value pairs in the Hash.
90
+ #
91
+ # ===Params
92
+ # * *obj* - The OpenStruct object to add Hash args to.
93
+ # * *hash* - The Hash to pull args from.
94
+ def add_hash(obj, hash)
95
+ return unless hash
96
+
97
+ hash.each do |key, value|
98
+ if value.class == Hash
99
+ eval "obj.#{key} = OpenStruct.new"
100
+ add_hash(eval("obj.#{key}"), value)
101
+ else
102
+ eval "obj.#{key.downcase} = value"
103
+ end
104
+ end
105
+ end
106
+
107
+ end
data/lib/string.rb ADDED
@@ -0,0 +1,48 @@
1
+ class String
2
+
3
+ # Allows various forms of string interpolation.
4
+ # Addd to make it easier to dynamically replace YAML config values;
5
+ # howerver, this will likely come in handy elsewhere.
6
+ #
7
+ # Examples:
8
+ # "Hello! My name is ?".interpolate("Nathan Hopkins")
9
+ # "Hello! My first name is ? and my last name is ?".interpolate(["Nathan", "Hopkins"])
10
+ # 'Hello! My first name is {first_name} and my last name is {last_name}'.interpolate(:first_name => "Nathan", :last_name => "Hopkins")
11
+ #
12
+ # ===Params
13
+ # * *args* [Symbol, String, Array, Hash] The value(s) used to replace segments of the string.
14
+ # * *in_place* [Boolean] Indicates if the value should edited in place.
15
+ # Be careful when doing this, you may end up with unexpected results!
16
+ #
17
+ # ===Returns
18
+ # The new string after interpolation.
19
+ def interpolate(args, in_place=false)
20
+ args = [args] unless args.is_a?(Array) || args.is_a?(Hash)
21
+
22
+ if args.is_a?(Array)
23
+ x = -1
24
+
25
+ if in_place
26
+ self.gsub!(/\?/) do |s|
27
+ x += 1
28
+ args[x]
29
+ end
30
+ else
31
+ return self.gsub(/\?/) do |s|
32
+ x += 1
33
+ args[x]
34
+ end
35
+ end
36
+ elsif args.is_a?(Hash)
37
+ if in_place
38
+ args.each {|k, v| self.gsub!(/\{#{k.to_s}\}/i, v.to_s)}
39
+ else
40
+ new_string = String.new(self)
41
+ args.each {|k, v| new_string.gsub!(/\{#{k.to_s}\}/i, v.to_s)}
42
+ return new_string
43
+ end
44
+ end
45
+
46
+ return self
47
+ end
48
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :fig do
3
+ # # Task goes here
4
+ # end
data/test/fig_test.rb ADDED
@@ -0,0 +1,89 @@
1
+ require 'test/unit'
2
+ require 'fileutils'
3
+ require File.dirname(__FILE__) + '/../lib/fig'
4
+
5
+ class FigTest < Test::Unit::TestCase
6
+ @@fig = Fig.new(File.dirname(__FILE__) + '/test.yml')
7
+
8
+ def test_yaml_values
9
+ assert @@fig.yaml
10
+ assert @@fig.yaml['name'] == 'Nathan Hopkins'
11
+ assert @@fig.yaml['message'] == 'Hello there Nathan Hopkins'
12
+ assert @@fig.yaml['name2'] == 'Page Hopkins'
13
+ assert @@fig.yaml['message2'] == 'Hello there Page Hopkins'
14
+ assert @@fig.yaml['list'].is_a?(Array)
15
+ assert @@fig.yaml['list'].length == 6
16
+ assert @@fig.yaml['parent']['name'] == 'Nathan Hopkins'
17
+ assert @@fig.yaml['parent']['child']['name'] == 'Emma Hopkins'
18
+
19
+ assert_raise NoMethodError do
20
+ @@fig.yaml['some']['complete']['garbage']
21
+ end
22
+ end
23
+
24
+ def test_settings_values
25
+ assert @@fig.settings
26
+ assert @@fig.settings.name == 'Nathan Hopkins'
27
+ assert @@fig.settings.message == 'Hello there Nathan Hopkins'
28
+ assert @@fig.settings.name2 == 'Page Hopkins'
29
+ assert @@fig.settings.message2 == 'Hello there Page Hopkins'
30
+ assert @@fig.settings.list.is_a?(Array)
31
+ assert @@fig.settings.list.length == 6
32
+ assert @@fig.settings.parent.name == 'Nathan Hopkins'
33
+ assert @@fig.settings.parent.child.name == 'Emma Hopkins'
34
+
35
+ assert_raise NoMethodError do
36
+ @@fig.settings.some.complete.garbage
37
+ end
38
+ end
39
+
40
+ def test_get_setting
41
+ assert @@fig.get_setting('name') == 'Nathan Hopkins'
42
+ assert @@fig.get_setting('message') == 'Hello there Nathan Hopkins'
43
+ assert @@fig.get_setting('name2') == 'Page Hopkins'
44
+ assert @@fig.get_setting('message2') == 'Hello there Page Hopkins'
45
+ assert @@fig.get_setting('list').is_a?(Array)
46
+ assert @@fig.get_setting('list').length == 6
47
+ assert @@fig.get_setting('parent').name == 'Nathan Hopkins'
48
+ assert @@fig.get_setting('parent').child.name == 'Emma Hopkins'
49
+ assert @@fig.get_setting('some.complete.garbage') == nil
50
+ end
51
+
52
+ def test_change_and_reload
53
+ dir_name = File.dirname(__FILE__)
54
+ orig_file = dir_name + '/test.yml'
55
+ new_file = dir_name + '/test2.yml'
56
+ bak_file = dir_name + '/test.yml.bak'
57
+
58
+ # make a backup
59
+ FileUtils.rm(bak_file) if File.exist?(bak_file)
60
+ FileUtils.cp orig_file, bak_file
61
+
62
+ # swap files
63
+ FileUtils.mv new_file, orig_file, :force => true
64
+
65
+ # verify that the file swap didn't change anything implicitly
66
+ test_get_setting
67
+
68
+ # reload
69
+ @@fig.load
70
+
71
+ # test new settings
72
+ assert @@fig.get_setting('name') == 'Jeff Hopkins'
73
+ assert @@fig.get_setting('message') == 'Hello there Jeff Hopkins'
74
+ assert @@fig.get_setting('name2') == 'Marie Hopkins'
75
+ assert @@fig.get_setting('message2') == 'Hello there Marie Hopkins'
76
+ assert @@fig.get_setting('list').is_a?(Array)
77
+ assert @@fig.get_setting('list').length == 6
78
+ assert @@fig.get_setting('parent').name == 'Jeff Hopkins'
79
+ assert @@fig.get_setting('parent').child.name == 'Nathan Hopkins'
80
+ assert @@fig.get_setting('some.complete.garbage') == nil
81
+
82
+ # switch back
83
+ FileUtils.mv orig_file, new_file, :force => true
84
+ FileUtils.mv bak_file, orig_file, :force => true
85
+ @@fig.load
86
+ end
87
+
88
+
89
+ end
@@ -0,0 +1,54 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/string'
3
+
4
+ class StringTest < Test::Unit::TestCase
5
+
6
+ def test_interpolate_with_string
7
+ orig = "Hello! My name is ?"
8
+ interpolated = orig.interpolate("Nathan Hopkins")
9
+ expected = "Hello! My name is Nathan Hopkins"
10
+ assert_not_equal orig, interpolated, "Should not have mutated in place"
11
+ assert_equal expected, interpolated
12
+
13
+ interpolated = orig.interpolate("Nathan Hopkins", true)
14
+ assert_equal orig, interpolated, "Should have mutated in place"
15
+ assert_equal expected, interpolated
16
+ end
17
+
18
+ def test_interpolate_with_symbol
19
+ orig = "Hello! My name is ?"
20
+ interpolated = orig.interpolate(:Nathan)
21
+ expected = "Hello! My name is Nathan"
22
+ assert_not_equal orig, interpolated, "Should not have mutated in place"
23
+ assert_equal expected, interpolated
24
+
25
+ interpolated = orig.interpolate(:Nathan, true)
26
+ assert_equal orig, interpolated, "Should have mutated in place"
27
+ assert_equal expected, interpolated
28
+ end
29
+
30
+ def test_interpolate_with_array
31
+ orig = "Hello! My first name is ? and my last name is ?"
32
+ interpolated = orig.interpolate(["Nathan", :Hopkins])
33
+ expected = "Hello! My first name is Nathan and my last name is Hopkins"
34
+ assert_not_equal orig, interpolated, "Should not have mutated in place"
35
+ assert_equal expected, interpolated
36
+
37
+ interpolated = orig.interpolate(["Nathan", :Hopkins], true)
38
+ assert_equal orig, interpolated, "Should have mutated in place"
39
+ assert_equal expected, interpolated
40
+ end
41
+
42
+ def test_interpolate_with_hash
43
+ orig = 'Hello! My first name is {first_name} and my last name is {last_name}'
44
+ interpolated = orig.interpolate(:first_name => "Nathan", :last_name => :Hopkins)
45
+ expected = "Hello! My first name is Nathan and my last name is Hopkins"
46
+ assert_not_equal orig, interpolated, "Should not have mutated in place"
47
+ assert_equal expected, interpolated
48
+
49
+ interpolated = orig.interpolate({:first_name => "Nathan", :last_name => :Hopkins}, true)
50
+ assert_equal orig, interpolated, "Should have mutated in place"
51
+ assert_equal expected, interpolated
52
+ end
53
+
54
+ end
data/test/suite.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/string_test'
3
+ require File.dirname(__FILE__) + '/fig_test'
data/test/test.yml ADDED
@@ -0,0 +1,9 @@
1
+ name: Nathan Hopkins
2
+ message: Hello there {fig:name}
3
+ message2: Hello there {fig:name2}
4
+ name2: Page Hopkins
5
+ list: [a, b, c, d, e, f]
6
+ parent:
7
+ name: '{fig:name}'
8
+ child:
9
+ name: Emma Hopkins
data/test/test2.yml ADDED
@@ -0,0 +1,9 @@
1
+ name: Jeff Hopkins
2
+ message: Hello there {fig:name}
3
+ message2: Hello there {fig:name2}
4
+ name2: Marie Hopkins
5
+ list: [a, b, c, d, e, f]
6
+ parent:
7
+ name: '{fig:name}'
8
+ child:
9
+ name: Nathan Hopkins
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: natehop-fig
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Hopkins
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-14 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: The smart way to manage configuration settings for your Ruby applications.
17
+ email: natehop@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ - lib/fig.rb
25
+ - lib/string.rb
26
+ - tasks/fig_tasks.rake
27
+ files:
28
+ - README.rdoc
29
+ - install.rb
30
+ - MIT-LICENSE
31
+ - test/test.yml
32
+ - test/suite.rb
33
+ - test/test2.yml
34
+ - test/string_test.rb
35
+ - test/fig_test.rb
36
+ - Manifest
37
+ - uninstall.rb
38
+ - Rakefile
39
+ - init.rb
40
+ - lib/fig.rb
41
+ - lib/string.rb
42
+ - tasks/fig_tasks.rake
43
+ - fig.gemspec
44
+ has_rdoc: true
45
+ homepage: http://github.com/natehop/fig
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --line-numbers
49
+ - --inline-source
50
+ - --title
51
+ - Fig
52
+ - --main
53
+ - README.rdoc
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "1.2"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project: fig
71
+ rubygems_version: 1.2.0
72
+ signing_key:
73
+ specification_version: 2
74
+ summary: The smart way to manage configuration settings for your Ruby applications.
75
+ test_files:
76
+ - test/string_test.rb
77
+ - test/fig_test.rb