settingslogic 2.0.3 → 2.0.5

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/README.rdoc CHANGED
@@ -1,6 +1,7 @@
1
1
  = Settingslogic
2
2
 
3
- Settingslogic is a simple configuration / settings solution that uses an ERB enabled YAML file. It has been great for my apps, maybe you will enjoy it too.
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.
4
5
 
5
6
  So here is my question to you.....is Settingslogic a great settings solution or the greatest?
6
7
 
@@ -10,43 +11,49 @@ So here is my question to you.....is Settingslogic a great settings solution or
10
11
  * <b>Repository:</b> http://github.com/binarylogic/settingslogic/tree/master
11
12
  * <b>Issues:</b> http://github.com/binarylogic/settingslogic/issues
12
13
 
13
- == Install and use
14
+ == Installation
14
15
 
15
- Install from rubyforge:
16
+ Install from rubyforge/gemcutter:
16
17
 
17
18
  sudo gem install settingslogic
18
19
 
19
- Install from github:
20
+ Or as a Rails plugin:
20
21
 
21
- sudo gem install binarylogic-settingslogic
22
+ script/plugin install git://github.com/binarylogic/settingslogic.git
22
23
 
23
- Or as a plugin
24
+ Settingslogic does not have any dependencies on Rails. Installing as a gem is recommended.
24
25
 
25
- script/plugin install git://github.com/binarylogic/settingslogic.git
26
+ == Usage
26
27
 
27
- == 1. Define your constant
28
+ === 1. Define your class
28
29
 
29
- Instead of defining a Settings constant for you, that task is left to you. Simply create a class in your application that looks like:
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:
30
32
 
31
33
  class Settings < Settingslogic
32
34
  source "#{Rails.root}/config/application.yml"
33
35
  namespace Rails.env
34
36
  end
35
37
 
36
- 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 this file in a rails app is models/settings.rb
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
37
40
 
38
41
  I felt adding a settings file in your app was more straightforward, less tricky, and more flexible.
39
42
 
40
- == 2. Create your settings
43
+ === 2. Create your settings
41
44
 
42
- Notice above we specified an absolute path to our settings file called "application.yml". This is just a typical YAML file. Also notice above that we specified a namespace for our environment. This allows us to namespace our configuration depending on our environment:
45
+ Notice above we specified an absolute path to our settings file called "application.yml". This is just a typical YAML file.
46
+ Also notice above that we specified a namespace for our environment. A namespace is just an optional string that corresponds
47
+ to a key in the YAML file.
48
+
49
+ Using a namespace allows us to change our configuration depending on our environment:
43
50
 
44
51
  # app/config/application.yml
45
52
  defaults: &defaults
46
53
  cool:
47
54
  saweet: nested settings
48
55
  neat_setting: 24
49
- awesome_setting: <%= "Did you know 5 + 5 = " + (5 + 5) + "?" %>
56
+ awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>
50
57
 
51
58
  development:
52
59
  <<: *defaults
@@ -58,11 +65,11 @@ Notice above we specified an absolute path to our settings file called "applicat
58
65
  production:
59
66
  <<: *defaults
60
67
 
61
- == Access your settings
68
+ === 3. Access your settings
69
+
70
+ >> Rails.env
71
+ => "development"
62
72
 
63
- >> Rails.env.development?
64
- => true
65
-
66
73
  >> Settings.cool
67
74
  => "#<Settingslogic::Settings ... >"
68
75
 
@@ -75,5 +82,64 @@ Notice above we specified an absolute path to our settings file called "applicat
75
82
  >> Settings.awesome_setting
76
83
  => "Did you know 5 + 5 = 10?"
77
84
 
85
+ You can use these settings anywhere, for example in a model:
86
+
87
+ class Post < ActiveRecord::Base
88
+ self.per_page = Settings.pagination.posts_per_page
89
+ end
90
+
91
+ === 4. Optional / dynamic settings
92
+
93
+ Often, you will want to handle defaults in your application logic itself, to reduce the number of settings
94
+ you need to put in your YAML file. You can access an optional setting by using Hash notation:
95
+
96
+ >> Settings.messaging.queue_name
97
+ => Exception: Missing setting 'queue_name' in 'message' section in 'application.yml'
98
+
99
+ >> Settings.messaging['queue_name']
100
+ => nil
101
+
102
+ >> Settings.messaging['queue_name'] ||= 'user_mail'
103
+ => "user_mail"
104
+
105
+ >> Settings.messaging.queue_name
106
+ => "user_mail"
107
+
108
+ Modifying our model example:
109
+
110
+ class Post < ActiveRecord::Base
111
+ self.per_page = Settings.posts['per_page'] || Settings.pagination.per_page
112
+ end
113
+
114
+ This would allow you to specify a custom value for per_page just for posts, or
115
+ to fall back to your default value if not specified.
116
+
117
+ == Note on Sinatra / Capistrano / Vlad
118
+
119
+ Each of these frameworks uses a +set+ convention for settings, which actually defines methods
120
+ in the global Object namespace:
121
+
122
+ set :application, "myapp" # does "def application" globally
123
+
124
+ This can cause collisions with Settingslogic, since those methods are global. Luckily, the
125
+ solution is to just add a call to load! in your class:
126
+
127
+ class Settings < Settingslogic
128
+ source "#{Rails.root}/config/application.yml"
129
+ namespace Rails.env
130
+ load!
131
+ end
132
+
133
+ It's probably always safest to add load! to your class, since this guarantees settings will be
134
+ loaded at that time, rather than lazily later via method_missing.
135
+
136
+ Finally, you can reload all your settings later as well:
137
+
138
+ Settings.reload!
139
+
140
+ This is useful if you want to support changing your settings YAML without restarting your app.
141
+
142
+ == Author
78
143
 
79
- Copyright (c) 2008 {Ben Johnson}[http://github.com/binarylogic] of {Binary Logic}[http://www.binarylogic.com], released under the MIT license
144
+ Copyright (c) 2008-2010 {Ben Johnson}[http://github.com/binarylogic] of {Binary Logic}[http://www.binarylogic.com],
145
+ released under the MIT license. Support for optional settings and reloading by {Nate Wiger}[http://nate.wiger.org].
data/Rakefile CHANGED
@@ -9,9 +9,8 @@ begin
9
9
  gem.email = "bjohnson@binarylogic.com"
10
10
  gem.homepage = "http://github.com/binarylogic/settingslogic"
11
11
  gem.authors = ["Ben Johnson of Binary Logic"]
12
- gem.rubyforge_project = "settingslogic"
13
12
  end
14
- Jeweler::RubyforgeTasks.new
13
+ Jeweler::GemcutterTasks.new
15
14
  rescue LoadError
16
15
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
17
16
  end
data/VERSION.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  ---
2
- :patch: 3
3
2
  :major: 2
4
3
  :minor: 0
4
+ :build:
5
+ :patch: 5
data/lib/settingslogic.rb CHANGED
@@ -3,6 +3,8 @@ require "erb"
3
3
 
4
4
  # A simple settings solution using a YAML file. See README for more information.
5
5
  class Settingslogic < Hash
6
+ class MissingSetting < StandardError; end
7
+
6
8
  class << self
7
9
  def name # :nodoc:
8
10
  instance.key?("name") ? instance.name : super
@@ -15,7 +17,7 @@ class Settingslogic < Hash
15
17
  @source = value
16
18
  end
17
19
  end
18
-
20
+
19
21
  def namespace(value = nil)
20
22
  if value.nil?
21
23
  @namespace
@@ -24,6 +26,26 @@ class Settingslogic < Hash
24
26
  end
25
27
  end
26
28
 
29
+ def [](key)
30
+ # Setting.key.value or Setting[:key][:value] or Setting['key']['value']
31
+ fetch(key.to_s,nil)
32
+ end
33
+
34
+ def []=(key,val)
35
+ # Setting[:key] = 'value' for dynamic settings
36
+ store(key.to_s,val)
37
+ end
38
+
39
+ def load!
40
+ instance
41
+ true
42
+ end
43
+
44
+ def reload!
45
+ @instance = nil
46
+ load!
47
+ end
48
+
27
49
  private
28
50
  def instance
29
51
  @instance ||= new
@@ -33,7 +55,7 @@ class Settingslogic < Hash
33
55
  instance.send(name, *args, &block)
34
56
  end
35
57
  end
36
-
58
+
37
59
  # Initializes a new settings object. You can initialize an object in any of the following ways:
38
60
  #
39
61
  # Settings.new(:application) # will look for config/application.yml
@@ -41,38 +63,51 @@ class Settingslogic < Hash
41
63
  # Settings.new("/var/configs/application.yml") # will look for /var/configs/application.yml
42
64
  # Settings.new(:config1 => 1, :config2 => 2)
43
65
  #
44
- # 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. If you pass a string it should be an absolute path to your settings file.
66
+ # Basically if you pass a symbol it will look for that file in the configs directory of your rails app,
67
+ # if you are using this in rails. If you pass a string it should be an absolute path to your settings file.
45
68
  # Then you can pass a hash, and it just allows you to access the hash via methods.
46
- def initialize(hash_or_file = self.class.source)
69
+ def initialize(hash_or_file = self.class.source, section = nil)
47
70
  case hash_or_file
48
71
  when Hash
49
- self.update hash_or_file
72
+ self.replace hash_or_file
50
73
  else
51
74
  hash = YAML.load(ERB.new(File.read(hash_or_file)).result).to_hash
52
75
  hash = hash[self.class.namespace] if self.class.namespace
53
- self.update hash
76
+ self.replace hash
54
77
  end
78
+ @section = section || hash_or_file # so end of error says "in application.yml"
79
+ create_accessors!
55
80
  end
56
-
57
- module EigenMethodDefiner # :nodoc:
58
- def method_missing(name, *args, &block)
59
- if key?(name.to_s)
60
- define_eigen_method(name.to_s)
61
- value = self[name.to_s]
62
- value.extend(EigenMethodDefiner) if value.is_a?(Hash)
63
- value
64
- else
65
- super
66
- end
67
- end
68
81
 
69
- private
82
+ # Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
83
+ # Otherwise, create_accessors! (called by new) will have created actual methods for each key.
84
+ def method_missing(key, *args, &block)
85
+ begin
86
+ value = fetch(key.to_s)
87
+ rescue IndexError
88
+ raise MissingSetting, "Missing setting '#{key}' in #{@section}"
89
+ end
90
+ value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value
91
+ end
70
92
 
71
- def define_eigen_method(name)
72
- eigen_class = class << self; self; end
73
- eigen_class.send(:define_method, name) { self[name] }
93
+ private
94
+ # This handles naming collisions with Sinatra/Vlad/Capistrano. Since these use a set()
95
+ # helper that defines methods in Object, ANY method_missing ANYWHERE picks up the Vlad/Sinatra
96
+ # settings! So settings.deploy_to title actually calls Object.deploy_to (from set :deploy_to, "host"),
97
+ # rather than the app_yml['deploy_to'] hash. Jeezus.
98
+ def create_accessors!
99
+ self.each do |key,val|
100
+ # Use instance_eval/class_eval because they're actually more efficient than define_method{}
101
+ # http://stackoverflow.com/questions/185947/ruby-definemethod-vs-def
102
+ # http://bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/
103
+ self.class.class_eval <<-EndEval
104
+ def #{key}
105
+ return @#{key} if @#{key} # cache (performance)
106
+ value = fetch('#{key}')
107
+ @#{key} = value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value
108
+ end
109
+ EndEval
74
110
  end
75
- end
111
+ end
76
112
 
77
- include EigenMethodDefiner
78
113
  end
@@ -1,15 +1,15 @@
1
1
  # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{settingslogic}
8
- s.version = "2.0.3"
8
+ s.version = "2.0.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ben Johnson of Binary Logic"]
12
- s.date = %q{2009-09-01}
12
+ s.date = %q{2010-02-01}
13
13
  s.email = %q{bjohnson@binarylogic.com}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE",
@@ -29,18 +29,19 @@ Gem::Specification.new do |s|
29
29
  "spec/settings.rb",
30
30
  "spec/settings.yml",
31
31
  "spec/settings2.rb",
32
+ "spec/settings3.rb",
32
33
  "spec/settingslogic_spec.rb",
33
34
  "spec/spec_helper.rb"
34
35
  ]
35
36
  s.homepage = %q{http://github.com/binarylogic/settingslogic}
36
37
  s.rdoc_options = ["--charset=UTF-8"]
37
38
  s.require_paths = ["lib"]
38
- s.rubyforge_project = %q{settingslogic}
39
39
  s.rubygems_version = %q{1.3.5}
40
40
  s.summary = %q{A simple and straightforward settings solution that uses an ERB enabled YAML file and a singleton design pattern.}
41
41
  s.test_files = [
42
42
  "spec/settings.rb",
43
43
  "spec/settings2.rb",
44
+ "spec/settings3.rb",
44
45
  "spec/settingslogic_spec.rb",
45
46
  "spec/spec_helper.rb"
46
47
  ]
@@ -55,3 +56,4 @@ Gem::Specification.new do |s|
55
56
  else
56
57
  end
57
58
  end
59
+
data/spec/settings.yml CHANGED
@@ -14,3 +14,6 @@ language:
14
14
  paradigm: functional
15
15
  smalltalk:
16
16
  paradigm: object oriented
17
+
18
+ collides:
19
+ does: not
data/spec/settings3.rb ADDED
@@ -0,0 +1,4 @@
1
+ class Settings3 < Settingslogic
2
+ source "#{File.dirname(__FILE__)}/settings.yml"
3
+ load! # test of load
4
+ end
@@ -1,10 +1,6 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
2
2
 
3
3
  describe "Settingslogic" do
4
- it "should be a hash" do
5
- Settings.send(:instance).should be_is_a(Hash)
6
- end
7
-
8
4
  it "should access settings" do
9
5
  Settings.setting2.should == 5
10
6
  end
@@ -16,21 +12,78 @@ describe "Settingslogic" do
16
12
  it "should access deep nested settings" do
17
13
  Settings.setting1.deep.another.should == "my value"
18
14
  end
19
-
15
+
20
16
  it "should access extra deep nested settings" do
21
17
  Settings.setting1.deep.child.value.should == 2
22
18
  end
23
-
19
+
24
20
  it "should enable erb" do
25
21
  Settings.setting3.should == 25
26
22
  end
27
23
 
28
24
  it "should namespace settings" do
29
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'
30
32
  end
31
33
 
32
34
  it "should distinguish nested keys" do
33
35
  Settings.language.haskell.paradigm.should == 'functional'
34
36
  Settings.language.smalltalk.paradigm.should == 'object oriented'
35
37
  end
38
+
39
+ it "should not collide with global methods" do
40
+ Settings3.collides.does.should == 'not'
41
+ end
42
+
43
+ it "should raise a helpful error message" do
44
+ e = nil
45
+ begin
46
+ Settings.missing
47
+ rescue => e
48
+ e.should be_kind_of Settingslogic::MissingSetting
49
+ end
50
+ e.should_not be_nil
51
+ e.message.should =~ /Missing setting 'missing' in/
52
+
53
+ e = nil
54
+ begin
55
+ Settings.language.missing
56
+ rescue => e
57
+ e.should be_kind_of Settingslogic::MissingSetting
58
+ end
59
+ e.should_not be_nil
60
+ e.message.should =~ /Missing setting 'missing' in 'language' section/
61
+ end
62
+
63
+ it "should handle optional / dynamic settings" do
64
+ e = nil
65
+ begin
66
+ Settings.language.erlang
67
+ rescue => e
68
+ e.should be_kind_of Settingslogic::MissingSetting
69
+ end
70
+ e.should_not be_nil
71
+ e.message.should =~ /Missing setting 'erlang' in 'language' section/
72
+
73
+ Settings.language['erlang'].should be_nil
74
+ Settings.language['erlang'] ||= 5
75
+ Settings.language['erlang'].should == 5
76
+
77
+ Settings.language['erlang'] = {'paradigm' => 'functional'}
78
+ Settings.language.erlang.paradigm.should == 'functional'
79
+
80
+ Settings.reload!
81
+ Settings.language['erlang'].should be_nil
82
+ end
83
+
84
+ # Put this test last or else call to .instance will load @instance,
85
+ # masking bugs.
86
+ it "should be a hash" do
87
+ Settings.send(:instance).should be_is_a(Hash)
88
+ end
36
89
  end
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,18 @@
1
1
  require 'spec'
2
2
  require 'rubygems'
3
- require 'ruby-debug'
3
+ require 'ruby-debug' if RUBY_VERSION < '1.9' # ruby-debug does not work on 1.9.1 yet
4
4
 
5
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
6
6
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
7
  require 'settingslogic'
8
8
  require 'settings'
9
9
  require 'settings2'
10
+ require 'settings3'
11
+
12
+ # Needed to test Settings3
13
+ def collides
14
+ 'collision'
15
+ end
10
16
 
11
17
  Spec::Runner.configure do |config|
12
18
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: settingslogic
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Johnson of Binary Logic
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-01 00:00:00 -05:00
12
+ date: 2010-02-01 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -36,6 +36,7 @@ files:
36
36
  - spec/settings.rb
37
37
  - spec/settings.yml
38
38
  - spec/settings2.rb
39
+ - spec/settings3.rb
39
40
  - spec/settingslogic_spec.rb
40
41
  - spec/spec_helper.rb
41
42
  has_rdoc: true
@@ -61,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
62
  version:
62
63
  requirements: []
63
64
 
64
- rubyforge_project: settingslogic
65
+ rubyforge_project:
65
66
  rubygems_version: 1.3.5
66
67
  signing_key:
67
68
  specification_version: 3
@@ -69,5 +70,6 @@ summary: A simple and straightforward settings solution that uses an ERB enabled
69
70
  test_files:
70
71
  - spec/settings.rb
71
72
  - spec/settings2.rb
73
+ - spec/settings3.rb
72
74
  - spec/settingslogic_spec.rb
73
75
  - spec/spec_helper.rb