siliconsalad-settingslogic 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ == 2.0.2 released 2009-08-22
2
+
3
+ * Define methods during method_missing instead of during initialization. Allows for modification on the fly.
4
+
5
+ == 2.0.0 released 2009-08-22
6
+
7
+ * Less magic, instead of automatically defining a Settings constant, you should define your own constant. See the readme for an example.
8
+
9
+ == 1.0.3 released 2009-04-23
10
+
11
+ * Fix Settings initialized with a Hash to work with both symbol and string hash keys.
12
+
13
+ == 1.0.2 released 2009-04-09
14
+
15
+ * Call key? off of the self in the class level name method.
16
+
17
+ == 1.0.1 released 2009-04-02
18
+
19
+ * Inherit from hash.
20
+
21
+ == 1.0.0 released 2008-12-05
22
+
23
+ * Only define methods if we have settings.
24
+
25
+ == 0.9.0 released 2008-10-30
26
+
27
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem 'rake'
5
+ gem 'jeweler'
6
+ gem 'rspec', :require => 'spec'
7
+ gem 'rcov'
8
+ if RUBY_VERSION < "1.9"
9
+ gem 'ruby-debug'
10
+ else
11
+ gem 'ruby-debug19'
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ archive-tar-minitar (0.5.2)
5
+ columnize (0.3.6)
6
+ diff-lcs (1.1.3)
7
+ git (1.2.5)
8
+ jeweler (1.6.4)
9
+ bundler (~> 1.0)
10
+ git (>= 1.2.5)
11
+ rake
12
+ linecache19 (0.5.12)
13
+ ruby_core_source (>= 0.1.4)
14
+ rake (0.9.2.2)
15
+ rcov (0.9.11)
16
+ rspec (2.8.0)
17
+ rspec-core (~> 2.8.0)
18
+ rspec-expectations (~> 2.8.0)
19
+ rspec-mocks (~> 2.8.0)
20
+ rspec-core (2.8.0)
21
+ rspec-expectations (2.8.0)
22
+ diff-lcs (~> 1.1.2)
23
+ rspec-mocks (2.8.0)
24
+ ruby-debug-base19 (0.11.25)
25
+ columnize (>= 0.3.1)
26
+ linecache19 (>= 0.5.11)
27
+ ruby_core_source (>= 0.1.4)
28
+ ruby-debug19 (0.11.6)
29
+ columnize (>= 0.3.1)
30
+ linecache19 (>= 0.5.11)
31
+ ruby-debug-base19 (>= 0.11.19)
32
+ ruby_core_source (0.1.5)
33
+ archive-tar-minitar (>= 0.5.2)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ jeweler
40
+ rake
41
+ rcov
42
+ rspec
43
+ ruby-debug19
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Ben Johnson of Binary Logic (binarylogic.com)
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.
@@ -0,0 +1,196 @@
1
+ = Settingslogic
2
+
3
+ Settingslogic is a simple configuration / settings solution that uses an ERB enabled YAML file. It has been great for
4
+ our apps, maybe you will enjoy it too. Settingslogic works with Rails, Sinatra, or any Ruby project.
5
+
6
+ So here is my question to you.....is Settingslogic a great settings solution or the greatest?
7
+
8
+ == Helpful links
9
+
10
+ * <b>Documentation:</b> http://rdoc.info/projects/binarylogic/settingslogic
11
+ * <b>Repository:</b> http://github.com/binarylogic/settingslogic/tree/master
12
+ * <b>Issues:</b> http://github.com/binarylogic/settingslogic/issues
13
+
14
+ == Installation
15
+
16
+ Install from rubyforge/gemcutter:
17
+
18
+ sudo gem install siliconsalad-settingslogic
19
+
20
+ Or as a Rails plugin:
21
+
22
+ script/plugin install git://github.com/binarylogic/settingslogic.git
23
+
24
+ Settingslogic does not have any dependencies on Rails. Installing as a gem is recommended.
25
+
26
+ == Usage
27
+
28
+ === 1. Define your class
29
+
30
+ Instead of defining a Settings constant for you, that task is left to you. Simply create a class in your application
31
+ that looks like:
32
+
33
+ class Settings < Settingslogic
34
+ source "#{Rails.root}/config/application.yml"
35
+ namespace Rails.env
36
+ end
37
+
38
+ Name it Settings, name it Config, name it whatever you want. Add as many or as few as you like. A good place to put
39
+ this file in a rails app is app/models/settings.rb
40
+
41
+ I felt adding a settings file in your app was more straightforward, less tricky, and more flexible.
42
+
43
+ If multiple files are passed on the source line, comma-separated, they will be loaded in order, with settings in later files overriding any existing keys. This allows you to, for instance, maintain a global settings file in source control, while allowing each developer to override individual settings as needed. Files that are specified but which do not exist will simply be ignored. Thus you can safely do the following without requiring the presence of application_local.yml:
44
+
45
+ class Settings < Settingslogic
46
+ source "#{Rails.root}/config/application.yml", "#{Rails.root}/config/application_local.yml"
47
+ namespace Rails.env
48
+ end
49
+
50
+ === 2. Create your settings
51
+
52
+ Notice above we specified an absolute path to our settings file called "application.yml". This is just a typical YAML file.
53
+ Also notice above that we specified a namespace for our environment. A namespace is just an optional string that corresponds
54
+ to a key in the YAML file.
55
+
56
+ Using a namespace allows us to change our configuration depending on our environment:
57
+
58
+ # config/application.yml
59
+ defaults: &defaults
60
+ cool:
61
+ saweet: nested settings
62
+ neat_setting: 24
63
+ awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>
64
+
65
+ development:
66
+ <<: *defaults
67
+ neat_setting: 800
68
+
69
+ test:
70
+ <<: *defaults
71
+
72
+ production:
73
+ <<: *defaults
74
+
75
+ _Note_: Certain Ruby/Bundler versions include a version of the Psych YAML parser which incorrectly handles merges (the `<<` in the example above.)
76
+ If your default settings seem to be overwriting your environment-specific settings, including the following lines in your config/boot.rb file may solve the problem:
77
+
78
+ require 'yaml'
79
+ YAML::ENGINE.yamler= 'syck'
80
+
81
+ === 3. Access your settings
82
+
83
+ >> Rails.env
84
+ => "development"
85
+
86
+ >> Settings.cool
87
+ => "#<Settingslogic::Settings ... >"
88
+
89
+ >> Settings.cool.saweet
90
+ => "nested settings"
91
+
92
+ >> Settings.neat_setting
93
+ => 800
94
+
95
+ >> Settings.awesome_setting
96
+ => "Did you know 5 + 5 = 10?"
97
+
98
+ You can use these settings anywhere, for example in a model:
99
+
100
+ class Post < ActiveRecord::Base
101
+ self.per_page = Settings.pagination.posts_per_page
102
+ end
103
+
104
+ === 4. Optional / dynamic settings
105
+
106
+ Often, you will want to handle defaults in your application logic itself, to reduce the number of settings
107
+ you need to put in your YAML file. You can access an optional setting by using Hash notation:
108
+
109
+ >> Settings.messaging.queue_name
110
+ => Exception: Missing setting 'queue_name' in 'message' section in 'application.yml'
111
+
112
+ >> Settings.messaging['queue_name']
113
+ => nil
114
+
115
+ >> Settings.messaging['queue_name'] ||= 'user_mail'
116
+ => "user_mail"
117
+
118
+ >> Settings.messaging.queue_name
119
+ => "user_mail"
120
+
121
+ Modifying our model example:
122
+
123
+ class Post < ActiveRecord::Base
124
+ self.per_page = Settings.posts['per_page'] || Settings.pagination.per_page
125
+ end
126
+
127
+ This would allow you to specify a custom value for per_page just for posts, or
128
+ to fall back to your default value if not specified.
129
+
130
+ === 5. Suppressing Exceptions Conditionally
131
+
132
+ Raising exceptions for missing settings helps highlight configuration problems. However, in a
133
+ Rails app it may make sense to suppress this in production and return nil for missing settings.
134
+ While it's useful to stop and highlight an error in development or test environments, this is
135
+ often not the right answer for production.
136
+
137
+ class Settings < Settingslogic
138
+ source "#{Rails.root}/config/application.yml"
139
+ namespace Rails.env
140
+ suppress_errors Rails.env.production?
141
+ end
142
+
143
+ >> Settings.non_existent_key
144
+ => nil
145
+
146
+ == Note on Sinatra / Capistrano / Vlad
147
+
148
+ Each of these frameworks uses a +set+ convention for settings, which actually defines methods
149
+ in the global Object namespace:
150
+
151
+ set :application, "myapp" # does "def application" globally
152
+
153
+ This can cause collisions with Settingslogic, since those methods are global. Luckily, the
154
+ solution is to just add a call to load! in your class:
155
+
156
+ class Settings < Settingslogic
157
+ source "#{Rails.root}/config/application.yml"
158
+ namespace Rails.env
159
+ load!
160
+ end
161
+
162
+ It's probably always safest to add load! to your class, since this guarantees settings will be
163
+ loaded at that time, rather than lazily later via method_missing.
164
+
165
+ Finally, you can reload all your settings later as well:
166
+
167
+ Settings.reload!
168
+
169
+ This is useful if you want to support changing your settings YAML without restarting your app.
170
+
171
+ == [new] Array of source files
172
+
173
+ This change allows you to set multiple source files. The main purpose behind adding it was to avoid the huge size of
174
+ application.yml. Now you can simply have 'defaults.yml', 'production.yml', 'development.yml' and so on. In your class
175
+ you can have something like:
176
+
177
+ class Settings < Settingslogic
178
+ source ["#{Rails.root}/config/settings/defaults.yml", "#{Rails.root}/config/settings/#{Rails.env}.yml"]
179
+ end
180
+
181
+ Sources are merged in the same order as they are positioned in the array; later settings overwrite earlier ones.
182
+ Deep merge is used, so settings will be merged on all levels.
183
+
184
+ == [new] Adding settings in the runtime
185
+
186
+ It is possible to add additional settings (hash, path_to_file or array_of_paths) by using Settings.load_source(hash_or_file_or_array, section, options).
187
+ This can be useful for example in case of a lib that needs settings. Lib can be loaded with its own settings which
188
+ can be later extended by part of application ones. It is possible to pass additional options:
189
+ - {:replace => true} to replace existing settings with the new ones
190
+ - {:deep_delete_nil => true} to deeply delete nil settings, ex. {:a=>{:b=>nil}}.deep_delete_nil => {}
191
+
192
+
193
+ == Author
194
+
195
+ Copyright (c) 2008-2010 {Ben Johnson}[http://github.com/binarylogic] of {Binary Logic}[http://www.binarylogic.com],
196
+ released under the MIT license. Support for optional settings and reloading by {Nate Wiger}[http://nate.wiger.org].
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "siliconsalad-settingslogic"
8
+ gem.summary = "A simple and straightforward settings solution that uses an ERB enabled YAML file and a singleton design pattern."
9
+ gem.email = "bjohnson@binarylogic.com"
10
+ gem.homepage = "http://github.com/siliconsalad/settingslogic"
11
+ gem.authors = ["Ben Johnson of Binary Logic"]
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
16
+ end
17
+
18
+ require 'rspec/core/rake_task'
19
+ RSpec::Core::RakeTask.new(:spec)
20
+
21
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
22
+ spec.pattern = 'spec/**/*_spec.rb'
23
+ spec.rcov = true
24
+ end
25
+
26
+ task :default => :spec
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 2
3
+ :minor: 0
4
+ :patch: 9
5
+ :build:
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
@@ -0,0 +1,225 @@
1
+ require "yaml"
2
+ require "erb"
3
+ require 'open-uri'
4
+
5
+ class Hash
6
+ def deep_merge!(other_hash)
7
+ other_hash.each_pair do |k,v|
8
+ tv = self[k]
9
+ self[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_merge!(v) : v
10
+ end
11
+ self
12
+ end
13
+
14
+ def deep_delete_nil
15
+ delete_if{|k, v| v.nil? or v.instance_of?(Hash) && v.deep_delete_nil.empty?}
16
+ end
17
+ end
18
+
19
+ # A simple settings solution using a YAML file. See README for more information.
20
+ class Settingslogic < Hash
21
+ class MissingSetting < StandardError; end
22
+ class InvalidSettingsFile < StandardError; end
23
+
24
+ class << self
25
+ def name # :nodoc:
26
+ self.superclass != Hash && instance.key?("name") ? instance.name : super
27
+ end
28
+
29
+ # Enables Settings.get('nested.key.name') for dynamic access
30
+ def get(key)
31
+ parts = key.split('.')
32
+ curs = self
33
+ while p = parts.shift
34
+ curs = curs.send(p)
35
+ end
36
+ curs
37
+ end
38
+
39
+ def source(value = nil)
40
+ #puts "source! #{value.inspect}"
41
+ if value.nil? || value.empty?
42
+ @source
43
+ else
44
+ @source = value
45
+ end
46
+ end
47
+
48
+ def namespace(value = nil)
49
+ if value.nil?
50
+ @namespace
51
+ else
52
+ @namespace = value
53
+ end
54
+ end
55
+
56
+ def suppress_errors(value = nil)
57
+ if value.nil?
58
+ @suppress_errors
59
+ else
60
+ @suppress_errors = value
61
+ end
62
+ end
63
+
64
+ def [](key)
65
+ instance.fetch(key.to_s, nil)
66
+ end
67
+
68
+ def []=(key, val)
69
+ # Setting[:key][:key2] = 'value' for dynamic settings
70
+ val = new(val, source) if val.is_a? Hash
71
+ instance.store(key.to_s, val)
72
+ instance.create_accessor_for(key, val)
73
+ end
74
+
75
+ def load!
76
+ instance
77
+ true
78
+ end
79
+
80
+ def reload!
81
+ @instance = nil
82
+ load!
83
+ end
84
+
85
+ private
86
+ def instance
87
+ return @instance if @instance
88
+ @instance = new
89
+ create_accessors!
90
+ @instance
91
+ end
92
+
93
+ def method_missing(name, *args, &block)
94
+ instance.send(name, *args, &block)
95
+ end
96
+
97
+ # It would be great to DRY this up somehow, someday, but it's difficult because
98
+ # of the singleton pattern. Basically this proxies Setting.foo to Setting.instance.foo
99
+ def create_accessors!
100
+ instance.each do |key,val|
101
+ create_accessor_for(key)
102
+ end
103
+ end
104
+
105
+ def create_accessor_for(key)
106
+ return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval
107
+ instance_eval "def #{key}; instance.send(:#{key}); end"
108
+ end
109
+
110
+ end
111
+
112
+ # Initializes a new settings object. You can initialize an object in any of the following ways:
113
+ #
114
+ # Settings.new(:application) # will look for config/application.yml
115
+ # Settings.new("application.yaml") # will look for application.yaml
116
+ # Settings.new("/var/configs/application.yml") # will look for /var/configs/application.yml
117
+ # Settings.new(:config1 => 1, :config2 => 2)
118
+ # Settings.new(["defaults.yml", "test.yml"]) # will look for defaults.yml and test.yml and merge them
119
+ #
120
+ # Basically if you pass a symbol it will look for that file in the configs directory of your rails app, if you are using this in rails.
121
+ # If you pass a string it should be an absolute path to your settings file.
122
+ # If you pass an array, it should have strings that are absolute paths to your settings files.
123
+ # Then you can pass a hash, and it just allows you to access the hash via methods.
124
+ #
125
+ # Options
126
+ # - deep_delete_nil: remove nil values from hash ex. {:a=>{:b=>nil}}.deep_delete_nil => {}
127
+ # - replace: if true, replace existing value, by new one, otherwise merge
128
+ def initialize(hash_or_file_or_array = self.class.source, section = nil, options={})
129
+ load_source(hash_or_file_or_array, section, {:replace => true}.merge(options))
130
+ end
131
+
132
+ def load_source(hash_or_file_or_array, section = nil, options={})
133
+ hash = case hash_or_file_or_array
134
+ when nil
135
+ raise Errno::ENOENT, "No file specified as Settingslogic source"
136
+ when Hash
137
+ hash_or_file_or_array
138
+ when Array
139
+ merge_settings_from_files(hash_or_file_or_array, options)
140
+ else
141
+ merge_settings_from_files([hash_or_file_or_array], options)
142
+ end
143
+ hash.deep_delete_nil if options[:deep_delete_nil]
144
+ options[:replace] ? self.replace(hash) : self.deep_merge!(hash)
145
+ @section = section || self.class.source # so end of error says "in application.yml"
146
+ create_accessors!
147
+ end
148
+
149
+ # For each array element - if file exists, parse it to hash
150
+ # if namespace is present take only specified part
151
+ def merge_settings_from_files(array, options={})
152
+ hash = array.inject({}) do |sum, file|
153
+ if File.exists?(file)
154
+ begin
155
+ tmp_hash = YAML.load(ERB.new(open(file).read).result).to_hash
156
+ if self.class.namespace
157
+ tmp_hash = tmp_hash[self.class.namespace] || {}
158
+ end
159
+ rescue
160
+ tmp_hash = {}
161
+ # https://github.com/tenderlove/psych/issues/23 (Psych::SyntaxError doesn't inherit from StandardError)
162
+ rescue Psych::SyntaxError
163
+ tmp_hash = {}
164
+ end
165
+ sum.deep_merge!(tmp_hash)
166
+ end
167
+ sum
168
+ end
169
+ raise InvalidSettingsFile, "No correct settings in any of files #{array.inspect}" if hash.empty?
170
+ hash
171
+ end
172
+
173
+ # Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
174
+ # Otherwise, create_accessors! (called by new) will have created actual methods for each key.
175
+ def method_missing(name, *args, &block)
176
+ key = name.to_s
177
+ return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? key
178
+ value = fetch(key)
179
+ create_accessor_for(key)
180
+ value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value
181
+ end
182
+
183
+ def [](key)
184
+ fetch(key.to_s, nil)
185
+ end
186
+
187
+ def []=(key,val)
188
+ # Setting[:key][:key2] = 'value' for dynamic settings
189
+ val = self.class.new(val, @section) if val.is_a? Hash
190
+ store(key.to_s, val)
191
+ create_accessor_for(key, val)
192
+ end
193
+
194
+ # This handles naming collisions with Sinatra/Vlad/Capistrano. Since these use a set()
195
+ # helper that defines methods in Object, ANY method_missing ANYWHERE picks up the Vlad/Sinatra
196
+ # settings! So settings.deploy_to title actually calls Object.deploy_to (from set :deploy_to, "host"),
197
+ # rather than the app_yml['deploy_to'] hash. Jeezus.
198
+ def create_accessors!
199
+ self.each do |key,val|
200
+ create_accessor_for(key)
201
+ end
202
+ end
203
+
204
+ # Use instance_eval/class_eval because they're actually more efficient than define_method{}
205
+ # http://stackoverflow.com/questions/185947/ruby-definemethod-vs-def
206
+ # http://bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/
207
+ def create_accessor_for(key, val=nil)
208
+ return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval
209
+ instance_variable_set("@#{key}", val) if val
210
+ self.class.class_eval <<-EndEval
211
+ def #{key}
212
+ return @#{key} if @#{key}
213
+ return missing_key("Missing setting '#{key}' in " + @section.to_s) unless has_key? '#{key}'
214
+ value = fetch('#{key}')
215
+ @#{key} = value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in "+ @section.to_s) : value
216
+ end
217
+ EndEval
218
+ end
219
+
220
+ def missing_key(msg)
221
+ return nil if self.class.suppress_errors
222
+
223
+ raise MissingSetting, msg
224
+ end
225
+ end
@@ -0,0 +1 @@
1
+ require "settingslogic"
@@ -0,0 +1,67 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "settingslogic"
8
+ s.version = "2.0.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ben Johnson of Binary Logic"]
12
+ s.date = "2012-02-27"
13
+ s.email = "bjohnson@binarylogic.com"
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "CHANGELOG.rdoc",
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION.yml",
26
+ "init.rb",
27
+ "lib/settingslogic.rb",
28
+ "rails/init.rb",
29
+ "settingslogic.gemspec",
30
+ "spec/settings.rb",
31
+ "spec/settings.yml",
32
+ "spec/settings2.yml",
33
+ "spec/settings3.yml",
34
+ "spec/settings_invalid.yml",
35
+ "spec/settingslogic_spec.rb",
36
+ "spec/spec_helper.rb"
37
+ ]
38
+ s.homepage = "http://github.com/siliconsalad/settingslogic"
39
+ s.require_paths = ["lib"]
40
+ s.rubygems_version = "1.8.10"
41
+ s.summary = "A simple and straightforward settings solution that uses an ERB enabled YAML file and a singleton design pattern."
42
+
43
+ if s.respond_to? :specification_version then
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
+ s.add_development_dependency(%q<rake>, [">= 0"])
48
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
49
+ s.add_development_dependency(%q<rspec>, [">= 0"])
50
+ s.add_development_dependency(%q<rcov>, [">= 0"])
51
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<rake>, [">= 0"])
54
+ s.add_dependency(%q<jeweler>, [">= 0"])
55
+ s.add_dependency(%q<rspec>, [">= 0"])
56
+ s.add_dependency(%q<rcov>, [">= 0"])
57
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
58
+ end
59
+ else
60
+ s.add_dependency(%q<rake>, [">= 0"])
61
+ s.add_dependency(%q<jeweler>, [">= 0"])
62
+ s.add_dependency(%q<rspec>, [">= 0"])
63
+ s.add_dependency(%q<rcov>, [">= 0"])
64
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
65
+ end
66
+ end
67
+
@@ -0,0 +1,68 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "siliconsalad-settingslogic"
8
+ s.version = "2.0.9"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ben Johnson of Binary Logic"]
12
+ s.date = "2012-02-27"
13
+ s.email = "bjohnson@binarylogic.com"
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "CHANGELOG.rdoc",
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION.yml",
26
+ "init.rb",
27
+ "lib/settingslogic.rb",
28
+ "rails/init.rb",
29
+ "settingslogic.gemspec",
30
+ "siliconsalad-settingslogic.gemspec",
31
+ "spec/settings.rb",
32
+ "spec/settings.yml",
33
+ "spec/settings2.yml",
34
+ "spec/settings3.yml",
35
+ "spec/settings_invalid.yml",
36
+ "spec/settingslogic_spec.rb",
37
+ "spec/spec_helper.rb"
38
+ ]
39
+ s.homepage = "http://github.com/siliconsalad/settingslogic"
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = "1.8.17"
42
+ s.summary = "A simple and straightforward settings solution that uses an ERB enabled YAML file and a singleton design pattern."
43
+
44
+ if s.respond_to? :specification_version then
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ s.add_development_dependency(%q<rake>, [">= 0"])
49
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
50
+ s.add_development_dependency(%q<rspec>, [">= 0"])
51
+ s.add_development_dependency(%q<rcov>, [">= 0"])
52
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<rake>, [">= 0"])
55
+ s.add_dependency(%q<jeweler>, [">= 0"])
56
+ s.add_dependency(%q<rspec>, [">= 0"])
57
+ s.add_dependency(%q<rcov>, [">= 0"])
58
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
59
+ end
60
+ else
61
+ s.add_dependency(%q<rake>, [">= 0"])
62
+ s.add_dependency(%q<jeweler>, [">= 0"])
63
+ s.add_dependency(%q<rspec>, [">= 0"])
64
+ s.add_dependency(%q<rcov>, [">= 0"])
65
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
66
+ end
67
+ end
68
+
@@ -0,0 +1,36 @@
1
+ class SettingsInst < Settingslogic
2
+ end
3
+
4
+ class Settings < Settingslogic
5
+ source "#{File.dirname(__FILE__)}/settings.yml"
6
+ end
7
+
8
+ class Settings2 < Settingslogic
9
+ source "#{File.dirname(__FILE__)}/settings.yml"
10
+ namespace "setting1"
11
+ end
12
+
13
+ class Settings3 < Settingslogic
14
+ source "#{File.dirname(__FILE__)}/settings.yml"
15
+ load! # test of load
16
+ end
17
+
18
+ # settings.yml, settings2.yml and settings3.yml should be merged
19
+ class Settings4 < Settingslogic
20
+ source ["#{File.dirname(__FILE__)}/settings.yml", "#{File.dirname(__FILE__)}/settings2.yml", "#{File.dirname(__FILE__)}/settings3.yml"]
21
+ end
22
+
23
+ # settings should be taken only from settings.yml
24
+ class Settings5 < Settingslogic
25
+ source ["#{File.dirname(__FILE__)}/settings_invalid.yml", "#{File.dirname(__FILE__)}/settings.yml", "#{File.dirname(__FILE__)}/non_exisiting.yml"]
26
+ end
27
+
28
+ # should raise an error - no valid settings file
29
+ class Settings6 < Settingslogic
30
+ source ["#{File.dirname(__FILE__)}/settings_invalid.yml", "#{File.dirname(__FILE__)}/non_exisiting.yml"]
31
+ end
32
+
33
+ class Settings7 < Settingslogic
34
+ source "#{File.dirname(__FILE__)}/settings.yml"
35
+ suppress_errors true
36
+ end
@@ -0,0 +1,27 @@
1
+ setting1:
2
+ setting1_child: saweet
3
+ deep:
4
+ another: my value
5
+ child:
6
+ value: 2
7
+
8
+ setting2: 5
9
+
10
+ setting3: <%= 5 * 5 %>
11
+ name: test
12
+
13
+ level0:
14
+ level1:
15
+ is: from_settings
16
+
17
+ language:
18
+ haskell:
19
+ paradigm: functional
20
+ smalltalk:
21
+ paradigm: object oriented
22
+
23
+ collides:
24
+ does: not
25
+ nested:
26
+ collides:
27
+ does: not either
@@ -0,0 +1,5 @@
1
+ setting2: overwritten!
2
+ setting4: from settings2.yml
3
+ level0:
4
+ level1:
5
+ is: from_settings2
@@ -0,0 +1 @@
1
+ another_setting: from settings3.yml
@@ -0,0 +1,2 @@
1
+ setting1: invalid_value
2
+ when: nesting
@@ -0,0 +1,208 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
2
+
3
+ describe "Settingslogic" do
4
+ it "should access settings" do
5
+ Settings.setting2.should == 5
6
+ end
7
+
8
+ it "should access nested settings" do
9
+ Settings.setting1.setting1_child.should == "saweet"
10
+ end
11
+
12
+ it "should access deep nested settings" do
13
+ Settings.setting1.deep.another.should == "my value"
14
+ end
15
+
16
+ it "should access extra deep nested settings" do
17
+ Settings.setting1.deep.child.value.should == 2
18
+ end
19
+
20
+ it "should enable erb" do
21
+ Settings.setting3.should == 25
22
+ end
23
+
24
+ it "should namespace settings" do
25
+ Settings2.setting1_child.should == "saweet"
26
+ Settings2.deep.another.should == "my value"
27
+ end
28
+
29
+ it "should return the namespace" do
30
+ Settings.namespace.should be_nil
31
+ Settings2.namespace.should == 'setting1'
32
+ end
33
+
34
+ it "should distinguish nested keys" do
35
+ Settings.language.haskell.paradigm.should == 'functional'
36
+ Settings.language.smalltalk.paradigm.should == 'object oriented'
37
+ end
38
+
39
+ it "should not collide with global methods" do
40
+ Settings3.nested.collides.does.should == 'not either'
41
+ Settings3[:nested] = 'fooey'
42
+ Settings3[:nested].should == 'fooey'
43
+ Settings3.nested.should == 'fooey'
44
+ Settings3.collides.does.should == 'not'
45
+ end
46
+
47
+ # multiple settings sources
48
+ it "should override previous settings with next in array" do
49
+ Settings4.setting2.should == "overwritten!"
50
+ end
51
+
52
+ it "should override previous settings with next in array (deep)" do
53
+ Settings4.level0.level1.is.should == "from_settings2"
54
+ end
55
+
56
+ it "should not raise error when at least one file is present and valid" do
57
+ Settings5.name.should == "test"
58
+ end
59
+
60
+ it "should raise an error when none of the files is present and valid" do
61
+ begin
62
+ Settings6.name
63
+ rescue => e
64
+ e.should be_kind_of Settingslogic::InvalidSettingsFile
65
+ end
66
+ end
67
+
68
+ it "should accept an array of file names as a source argument and load all of them" do
69
+ Settings4.setting1.setting1_child.should == "saweet"
70
+ Settings4.setting4.should == "from settings2.yml"
71
+ Settings4.another_setting.should == "from settings3.yml"
72
+ end
73
+
74
+ # loading additional settings in the runtime
75
+ it "should merge hash into existing settings" do
76
+ Settings.load_source({"level0" => {"level1" => {"added" => 'this'}}})
77
+ Settings.level0.level1.is.should == 'from_settings'
78
+ Settings.level0.level1.added.should == 'this'
79
+ end
80
+
81
+ it "should merge file into existing settings" do
82
+ Settings.load_source("#{File.dirname(__FILE__)}/settings2.yml")
83
+ Settings.setting1.setting1_child.should == "saweet"
84
+ Settings.setting4.should == "from settings2.yml"
85
+ end
86
+
87
+ it "should merge array of files into existing settings" do
88
+ Settings.load_source(["#{File.dirname(__FILE__)}/settings2.yml", "#{File.dirname(__FILE__)}/settings3.yml"])
89
+ Settings.setting1.setting1_child.should == "saweet"
90
+ Settings.another_setting.should == "from settings3.yml"
91
+ end
92
+
93
+ it "should raise a helpful error message" do
94
+ e = nil
95
+ begin
96
+ Settings.missing
97
+ rescue => e
98
+ e.should be_kind_of Settingslogic::MissingSetting
99
+ end
100
+ e.should_not be_nil
101
+ e.message.should =~ /Missing setting 'missing' in/
102
+
103
+ e = nil
104
+ begin
105
+ Settings.language.missing
106
+ rescue => e
107
+ e.should be_kind_of Settingslogic::MissingSetting
108
+ end
109
+ e.should_not be_nil
110
+ e.message.should =~ /Missing setting 'missing' in 'language' section/
111
+ end
112
+
113
+ it "should handle optional / dynamic settings" do
114
+ e = nil
115
+ begin
116
+ Settings.language.erlang
117
+ rescue => e
118
+ e.should be_kind_of Settingslogic::MissingSetting
119
+ end
120
+ e.should_not be_nil
121
+ e.message.should =~ /Missing setting 'erlang' in 'language' section/
122
+
123
+ Settings.language['erlang'].should be_nil
124
+ Settings.language['erlang'] = 5
125
+ Settings.language['erlang'].should == 5
126
+
127
+ Settings.language['erlang'] = {'paradigm' => 'functional'}
128
+ Settings.language.erlang.paradigm.should == 'functional'
129
+ Settings.respond_to?('erlang').should be_false
130
+
131
+ Settings.reload!
132
+ Settings.language['erlang'].should be_nil
133
+
134
+ Settings.language[:erlang] ||= 5
135
+ Settings.language[:erlang].should == 5
136
+
137
+ Settings.language[:erlang] = {}
138
+ Settings.language[:erlang][:paradigm] = 'functional'
139
+ Settings.language.erlang.paradigm.should == 'functional'
140
+
141
+ Settings[:toplevel] = '42'
142
+ Settings.toplevel.should == '42'
143
+ end
144
+
145
+ it "should raise an error on a nil source argument" do
146
+ class NoSource < Settingslogic; end
147
+ e = nil
148
+ begin
149
+ NoSource.foo.bar
150
+ rescue => e
151
+ e.should be_kind_of Errno::ENOENT
152
+ end
153
+ e.should_not be_nil
154
+ end
155
+
156
+ it "should allow suppressing errors" do
157
+ Settings7.non_existent_key.should be_nil
158
+ end
159
+
160
+ # This one edge case currently does not pass, because it requires very
161
+ # esoteric code in order to make it pass. It was judged not worth fixing,
162
+ # as it introduces significant complexity for minor gain.
163
+ # it "should handle reloading top-level settings"
164
+ # Settings[:inspect] = 'yeah baby'
165
+ # Settings.inspect.should == 'yeah baby'
166
+ # Settings.reload!
167
+ # Settings.inspect.should == 'Settings'
168
+ # end
169
+
170
+ it "should handle oddly-named settings" do
171
+ Settings.language['some-dash-setting#'] = 'dashtastic'
172
+ Settings.language['some-dash-setting#'].should == 'dashtastic'
173
+ end
174
+
175
+ it "should support instance usage as well" do
176
+ settings = SettingsInst.new(Settings.source)
177
+ settings.setting1.setting1_child.should == "saweet"
178
+ end
179
+
180
+ it "should be able to get() a key with dot.notation" do
181
+ Settings.get('setting1.setting1_child').should == "saweet"
182
+ Settings.get('setting1.deep.another').should == "my value"
183
+ Settings.get('setting1.deep.child.value').should == 2
184
+ end
185
+
186
+ # If .name is not a property, delegate to superclass
187
+ it "should respond with Module.name" do
188
+ Settings2.name.should == "Settings2"
189
+ end
190
+
191
+ # If .name is called on Settingslogic itself, handle appropriately
192
+ # by delegating to Hash
193
+ it "should have the parent class always respond with Module.name" do
194
+ Settingslogic.name.should == 'Settingslogic'
195
+ end
196
+
197
+ # If .name is a property, respond with that instead of delegating to superclass
198
+ it "should allow a name setting to be overriden" do
199
+ Settings.name.should == 'test'
200
+ end
201
+
202
+ # Put this test last or else call to .instance will load @instance,
203
+ # masking bugs.
204
+ it "should be a hash" do
205
+ Settings.send(:instance).should be_is_a(Hash)
206
+ end
207
+
208
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rspec'
4
+ require 'settingslogic'
5
+ require 'settings'
6
+
7
+ # Needed to test Settings3
8
+ Object.send :define_method, 'collides' do
9
+ 'collision'
10
+ end
11
+
12
+ RSpec.configure do |config|
13
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: siliconsalad-settingslogic
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.9
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ben Johnson of Binary Logic
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70122421875020 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70122421875020
25
+ - !ruby/object:Gem::Dependency
26
+ name: jeweler
27
+ requirement: &70122422223700 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70122422223700
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70122422219820 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70122422219820
47
+ - !ruby/object:Gem::Dependency
48
+ name: rcov
49
+ requirement: &70122422218780 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70122422218780
58
+ - !ruby/object:Gem::Dependency
59
+ name: ruby-debug19
60
+ requirement: &70122422217280 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70122422217280
69
+ description:
70
+ email: bjohnson@binarylogic.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files:
74
+ - LICENSE
75
+ - README.rdoc
76
+ files:
77
+ - CHANGELOG.rdoc
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - LICENSE
81
+ - README.rdoc
82
+ - Rakefile
83
+ - VERSION.yml
84
+ - init.rb
85
+ - lib/settingslogic.rb
86
+ - rails/init.rb
87
+ - settingslogic.gemspec
88
+ - siliconsalad-settingslogic.gemspec
89
+ - spec/settings.rb
90
+ - spec/settings.yml
91
+ - spec/settings2.yml
92
+ - spec/settings3.yml
93
+ - spec/settings_invalid.yml
94
+ - spec/settingslogic_spec.rb
95
+ - spec/spec_helper.rb
96
+ homepage: http://github.com/siliconsalad/settingslogic
97
+ licenses: []
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 1.8.17
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: A simple and straightforward settings solution that uses an ERB enabled YAML
120
+ file and a singleton design pattern.
121
+ test_files: []