diff -Nru ruby-configurate-0.0.2/.gitignore ruby-configurate-0.0.8/.gitignore --- ruby-configurate-0.0.2/.gitignore 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -*.gem diff -Nru ruby-configurate-0.0.2/.rspec ruby-configurate-0.0.8/.rspec --- ruby-configurate-0.0.2/.rspec 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/.rspec 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ ---color ---format progress diff -Nru ruby-configurate-0.0.2/.rvmrc ruby-configurate-0.0.8/.rvmrc --- ruby-configurate-0.0.2/.rvmrc 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/.rvmrc 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -rvm use --create 1.9.3-p327@configurate diff -Nru ruby-configurate-0.0.2/.travis.yml ruby-configurate-0.0.8/.travis.yml --- ruby-configurate-0.0.2/.travis.yml 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -language: ruby - -rvm: - - 1.9.2 - - 1.9.3 - - jruby-19mode - - rbx-19mode diff -Nru ruby-configurate-0.0.2/Changelog.md ruby-configurate-0.0.8/Changelog.md --- ruby-configurate-0.0.2/Changelog.md 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/Changelog.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -# 0.0.2 - -## Bug fixes - -* Return duplicates from the environment provider so that the return value can be modified by the client. - -# 0.0.1 - -* Initial release diff -Nru ruby-configurate-0.0.2/Gemfile ruby-configurate-0.0.8/Gemfile --- ruby-configurate-0.0.2/Gemfile 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/Gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -source 'https://rubygems.org' - -group :development, :test do - gem 'rake', '~> 10.0.3' - gem 'rspec', '~> 2.12.0' -end diff -Nru ruby-configurate-0.0.2/Gemfile.lock ruby-configurate-0.0.8/Gemfile.lock --- ruby-configurate-0.0.2/Gemfile.lock 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/Gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - diff-lcs (1.1.3) - rake (10.0.3) - rspec (2.12.0) - rspec-core (~> 2.12.0) - rspec-expectations (~> 2.12.0) - rspec-mocks (~> 2.12.0) - rspec-core (2.12.2) - rspec-expectations (2.12.1) - diff-lcs (~> 1.1.3) - rspec-mocks (2.12.1) - -PLATFORMS - ruby - -DEPENDENCIES - rake (~> 10.0.3) - rspec (~> 2.12.0) diff -Nru ruby-configurate-0.0.2/LICENSE ruby-configurate-0.0.8/LICENSE --- ruby-configurate-0.0.2/LICENSE 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Copyright (c) 2012 Jonne Haß - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff -Nru ruby-configurate-0.0.2/README.md ruby-configurate-0.0.8/README.md --- ruby-configurate-0.0.2/README.md 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/README.md 2013-06-05 09:22:43.000000000 +0000 @@ -1,9 +1,78 @@ # Configurate - A flexible configuration system +[![Gem Version](https://badge.fury.io/rb/configurate.png)](https://rubygems.org/gems/configurate) [![Build Status](https://secure.travis-ci.org/MrZYX/configurate.png?branch=master)](https://travis-ci.org/MrZYX/configurate) [![Gemnasium](https://gemnasium.com/MrZYX/configurate.png)](https://gemnasium.com/MrZYX/configurate) -[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/MrZYX/configurate) +[![Code Climate](https://codeclimate.com/github/MrZYX/configurate.png)](https://codeclimate.com/github/MrZYX/configurate) +[![Coverage Status](https://coveralls.io/repos/MrZYX/configurate/badge.png?branch=master)](https://coveralls.io/r/MrZYX/configurate) -Docs and Readme are WIP. Just one gotcha if you want to use it straight away: +Configurate allows you to specify a chain of configuration providers which are +queried in order until one returns a value. This allows scenarios like overriding +your default settings with a user configuration file and let those be overridden +by environment variables. The query interface allows to group and nest your configuration options +to a practically unlimited level. + +Configurate works with Ruby 1.9.2 or later. + +## Installation + +Just add + +```ruby +gem 'configurate' +``` + +to your `Gemfile`. + + +## Usage + +A basic loader could look like this: + +```ruby +require 'configurate' + +Config = Configurate::Settings.create do + add_provider Configurate::Provider::Env + add_provider Configurate::Provider::YAML, '/etc/app_settings.yml', + namespace: Rails.env, required: false + add_provider Configurate::Provider::YAML, 'config/default_settings.yml' +end + +# Somewhere later +if Config.remote_assets.enable? + set_asset_host Config.remote_assets.host +end +``` + +You can add custom methods working with your settings to your `Configurate::Settings` instance +by calling `extend YourConfigurationMethods` inside the block passed to `#create`. + +Providers are called in the order they're added. You can already use the added providers to +determine if further ones should be added: + +```ruby +require 'configurate' + +Config = Configurate::Settings.create do + add_provider Configurate::Provider::Env + add_provider Configurate::Provider::YAML, 'config/settings.yml' unless heroku? +end +``` + +`add_provider` can be called later on the created object to add more providers to the chain. +It takes a constant and parameters that should be passed to the initializer. + +A providers only requirement is that it responds to the `#lookup` method. `#lookup` is passed the current +`SettingPath`, for example for a call to `Config.foo.bar.baz?` it gets a path with the items `'foo'`, `'bar'`, `'baz'` passed. `SettingPath` behaves like `Array` with some methods added. +The provider should raise `Configurate::SettingNotFoundError` if it can't provide a value for the requested option. +Any additional parameters are passed along to the provider, thus a `#lookup` method must be able to take +any number of additional parameters. + +You're not limited to one instance of the configuration object. + +## Gotchas + +### False Ruby does not allow to metaprogram `false`, thus something like @@ -18,4 +87,108 @@ puts "yep" if Config.enable_stuff? ``` -Meanwhile checkout the [docs](http://rubydoc.info/github/MrZYX/configurate/master/frames/index). +### Module#=== + +Another thing you can't overwrite in Ruby is the `===` operator, rendering case statements useless + +```ruby +puts case Config.some.setting + when NilClass + "nil" + when String + "string" + else + "unknown" + end +``` + +will always output `unknown`. Again use `.get` + + +## Shipped providers + +### Configurate::Provider::Base + +A convenience base class changing the interface for implementers. It provides a basic `#lookup` method +which just passes all parameters through to `#lookup_path`. +The result of `#lookup_path` is returned, unless it's `nil` +then `Configurate::SettingNotFoundError` is raised. Subclasses are expected to implement `#lookup_path`. +Do not use this class directly as a provider! + +### Configurate::Provider::Env + +This class transforms a query string into a name for a environment variable and looks up this variable then. +The conversion scheme is the following: Convert to uppercase, join path with underscores. So for example `Config.foo.bar.baz` +would look for a environment variable named `FOO_BAR_BAZ`. Additionally it splits comma separated values +into arrays. + +This provider does not take any additional initialization parameters. + +### Configurate::Provider::YAML + +This provider reads settings from a given [YAML](http://www.yaml.org) file. It converts the sections of +query string to a nested value. For a given YAML file + +```yaml +stuff: + enable: true + param: "foo" + nested: + param: "bar" +``` + +the following queries would be valid: + +```ruby +Config.stuff.enable? # => true +Config.stuff.param # => "foo" +Config.stuff.nested.param # => "bar" +``` + +The initializer takes a path to the configuration file as mandatory first argument and +the following optional parameters, as a hash: + +* *namespace:* Specify a alternative root. This is useful if you for example add the same file multiple + times through multiple providers, with different namespaces, letting you override settings depending on + the rails environment, without duplicating common settings. Defaults to none. +* *required:* Whether to raise an error if the the file isn't found or, if one is given, the namespace + doesn't exist in the file. + +### Configurate::Provider::Dynamic + +A provider which stores the first additonal parameter if the query string ends with an equal sign and can +return it later. This is mainly useful for testing but can be useful to temporarily overide stuff +too. To clarify a small example: + +```ruby +Config.foo.bar # => nil +Config.foo.bar = "baz" +Config.foo.bar # => "baz" +``` + +## Writing a provider + +...should be pretty easy. For example here is the `Configurate::Provider::Env` provider: + +```ruby +class Configurate::Provider::Env < Configurate::Provider::Base + def lookup_path(setting_path, *args) + value = ENV[setting_path.join("_").upcase] + unless value.nil? + value = value.dup + value = value.split(",") if value.include?(",") + end + value + end +end +``` + + +## Documentation + +You can find the current documentation for the master branch [here](http://rubydoc.info/github/MrZYX/configurate/master/frames/index). + + +## License + +MIT, see [LICENSE](./LICENSE) diff -Nru ruby-configurate-0.0.2/Rakefile ruby-configurate-0.0.8/Rakefile --- ruby-configurate-0.0.2/Rakefile 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/Rakefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -require 'rspec/core/rake_task' - -RSpec::Core::RakeTask.new(:rspec) - -task default: :rspec diff -Nru ruby-configurate-0.0.2/configurate.gemspec ruby-configurate-0.0.8/configurate.gemspec --- ruby-configurate-0.0.2/configurate.gemspec 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/configurate.gemspec 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -Gem::Specification.new do |s| - s.name = 'configurate' - s.version = '0.0.2' - s.summary = "Flexbile configuration system" - s.description = "Configurate is a flexible configuration system that can read settings from multiple sources at the same time." - s.authors = ["Jonne Haß"] - s.email = "me@mrzyx.de" - s.files = Dir["lib/**/*.rb"] - s.homepage = "https://github.com/MrZYX/configurate" - s.license = "MIT" - s.required_ruby_version = '~> 1.9.2' -end diff -Nru ruby-configurate-0.0.2/data.tar.gz.asc ruby-configurate-0.0.8/data.tar.gz.asc --- ruby-configurate-0.0.2/data.tar.gz.asc 1970-01-01 00:00:00.000000000 +0000 +++ ruby-configurate-0.0.8/data.tar.gz.asc 2013-06-05 09:22:43.000000000 +0000 @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.20 (GNU/Linux) + +iQEcBAABAgAGBQJRrlMbAAoJEPNH4OtHrHDWnC0H/RMF7kn/MJ6sDIugAmWQXK43 +BGyu3+oXLhDPkTOh090/xhajnDh2FqOFVgzdpJRTLkzffC5boy6gOw4c0FeOZJob +Vm0SiaBBv6qY9PNhUjjcvIH611oaAU/5WLqydCKPl49WKmhd4LGoH/iTnKWeVJWs +QPrYytfL7YDb8r0zAM/iQ39QI0Wtm+abPSY4zlBv5ZgkyRpbchYC7h7oetJYG9A1 +C8MmoKBA2+aIrWomCcPWTcpuDTFV41Kyrrts7y/4KVc/bpnZo6t56mWmiFDtiMOi +WQ13Z49/2yMeLIQs5GW98ZS8r2EdkcW+ZzIJQuL7nPGmRqlRFgzs212qc/0gx/Y= +=+Q/C +-----END PGP SIGNATURE----- diff -Nru ruby-configurate-0.0.2/debian/changelog ruby-configurate-0.0.8/debian/changelog --- ruby-configurate-0.0.2/debian/changelog 2013-03-02 15:49:49.000000000 +0000 +++ ruby-configurate-0.0.8/debian/changelog 2013-06-12 08:09:33.000000000 +0000 @@ -1,3 +1,9 @@ +ruby-configurate (0.0.8-1) unstable; urgency=low + * Team upload. + * New Upstream Release + + -- Nitesh A Jain Wed, 05 Jun 2013 14:55:17 +0530 + ruby-configurate (0.0.2-1) unstable; urgency=low * Initial release (Closes: #701530) diff -Nru ruby-configurate-0.0.2/debian/ruby-configurate.docs ruby-configurate-0.0.8/debian/ruby-configurate.docs --- ruby-configurate-0.0.2/debian/ruby-configurate.docs 1970-01-01 00:00:00.000000000 +0000 +++ ruby-configurate-0.0.8/debian/ruby-configurate.docs 2013-06-12 08:05:24.000000000 +0000 @@ -0,0 +1 @@ + README.md diff -Nru ruby-configurate-0.0.2/debian/rules ruby-configurate-0.0.8/debian/rules --- ruby-configurate-0.0.2/debian/rules 2013-03-02 21:24:27.000000000 +0000 +++ ruby-configurate-0.0.8/debian/rules 2013-06-12 08:05:24.000000000 +0000 @@ -13,6 +13,3 @@ %: dh $@ --buildsystem=ruby --with ruby - -override_dh_installchangelogs: - dh_installchangelogs Changelog.md diff -Nru ruby-configurate-0.0.2/lib/configurate/lookup_chain.rb ruby-configurate-0.0.8/lib/configurate/lookup_chain.rb --- ruby-configurate-0.0.2/lib/configurate/lookup_chain.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/lib/configurate/lookup_chain.rb 2013-06-05 09:22:43.000000000 +0000 @@ -1,12 +1,12 @@ module Configurate # This object builds a chain of configuration providers to try to find - # a setting. + # the value of a setting. class LookupChain def initialize @provider = [] end - # Add a provider to the chain. Providers are tried in the order + # Adds a provider to the chain. Providers are tried in the order # they are added, so the order is important. # # @param provider [#lookup] @@ -25,17 +25,16 @@ # Tries all providers in the order they were added to provide a response # for setting. # - # @param setting [#to_s] settings should be underscore_case, - # nested settings should be separated by a dot - # @param *args further args passed to the provider - # @return [Array,String,Boolean,nil] whatever the provider provides - # is casted to a {String}, except for some special values + # @param setting [SettingPath,String] nested settings as strings should + # be separated by a dot + # @param ... further args passed to the provider + # @return [Array,Hash,String,Boolean,nil] whatever the responding + # provider provides is casted to a {String}, except for some special values def lookup(setting, *args) - setting = setting.to_s - + setting = SettingPath.new setting if setting.is_a? String @provider.each do |provider| begin - return special_value_or_string(provider.lookup(setting, *args)) + return special_value_or_string(provider.lookup(setting.clone, *args)) rescue SettingNotFoundError; end end diff -Nru ruby-configurate-0.0.2/lib/configurate/provider/dynamic.rb ruby-configurate-0.0.8/lib/configurate/provider/dynamic.rb --- ruby-configurate-0.0.2/lib/configurate/provider/dynamic.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/lib/configurate/provider/dynamic.rb 2013-06-05 09:22:43.000000000 +0000 @@ -8,11 +8,10 @@ @settings = {} end - def lookup_path(settings_path, *args) - key = settings_path.join(".") + def lookup_path(setting_path, *args) + key = setting_path.to_s - if key.end_with?("=") && args.length > 0 - key = key.chomp("=") + if setting_path.is_setter? && args.length > 0 value = args.first value = value.get if value.respond_to?(:_proxy?) && value._proxy? @settings[key] = value diff -Nru ruby-configurate-0.0.2/lib/configurate/provider/env.rb ruby-configurate-0.0.8/lib/configurate/provider/env.rb --- ruby-configurate-0.0.2/lib/configurate/provider/env.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/lib/configurate/provider/env.rb 2013-06-05 09:22:43.000000000 +0000 @@ -1,14 +1,16 @@ module Configurate; module Provider # This provider looks for settings in the environment. # For the setting +foo.bar_baz+ this provider will look for an - # environment variable +FOO_BAR_BAZ+, replacing all dots in the setting - # and upcasing the result. If an value contains +,+ it's split at them - # and returned as array. + # environment variable +FOO_BAR_BAZ+, joining all components of the + # setting with underscores and upcasing the result. + # If an value contains any commas (,) it's split at them and returned as array. class Env < Base - def lookup_path(settings_path, *args) - value = ENV[settings_path.join("_").upcase] - value = value.dup unless value.nil? - value = value.split(",") if value && value.include?(",") + def lookup_path(setting_path, *args) + value = ENV[setting_path.join("_").upcase] + unless value.nil? + value = value.dup + value = value.split(",") if value.include?(",") + end value end end diff -Nru ruby-configurate-0.0.2/lib/configurate/provider/yaml.rb ruby-configurate-0.0.8/lib/configurate/provider/yaml.rb --- ruby-configurate-0.0.2/lib/configurate/provider/yaml.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/lib/configurate/provider/yaml.rb 2013-06-05 09:22:43.000000000 +0000 @@ -1,7 +1,7 @@ require 'yaml' module Configurate; module Provider - # This provider tries to open a YAML file and does in nested lookups + # This provider tries to open a YAML file and does nested lookups # in it. class YAML < Base # @param file [String] the path to the file @@ -13,40 +13,36 @@ # @raise [Errno:ENOENT] if the file isn't found def initialize(file, opts = {}) @settings = {} - required = opts.has_key?(:required) ? opts.delete(:required) : true + required = opts.delete(:required) { true } @settings = ::YAML.load_file(file) namespace = opts.delete(:namespace) unless namespace.nil? - actual_settings = lookup_in_hash(namespace.split("."), @settings) - unless actual_settings.nil? - @settings = actual_settings - else + @settings = lookup_in_hash(SettingPath.new(namespace), @settings) do raise ArgumentError, "Namespace #{namespace} not found in #{file}" if required + $stderr.puts "WARNING: Namespace #{namespace} not found in #{file}" end end rescue Errno::ENOENT => e - $stderr.puts "WARNING: configuration file #{file} not found, ensure it's present" + $stderr.puts "WARNING: Configuration file #{file} not found, ensure it's present" raise e if required end - def lookup_path(settings_path, *args) - lookup_in_hash(settings_path, @settings) + def lookup_path(setting_path, *) + lookup_in_hash(setting_path, @settings) end private - def lookup_in_hash(setting_path, hash) - setting = setting_path.shift - if hash.has_key?(setting) - if setting_path.length > 0 && hash[setting].is_a?(Hash) - return lookup_in_hash(setting_path, hash[setting]) if setting.length > 1 - else - return hash[setting] - end + def lookup_in_hash(setting_path, hash, &fallback) + fallback ||= proc { nil } + while hash.is_a?(Hash) && hash.has_key?(setting_path.first) && !setting_path.empty? + hash = hash[setting_path.shift] end + return fallback.call unless setting_path.empty? + hash end end end; end diff -Nru ruby-configurate-0.0.2/lib/configurate/provider.rb ruby-configurate-0.0.8/lib/configurate/provider.rb --- ruby-configurate-0.0.2/lib/configurate/provider.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/lib/configurate/provider.rb 2013-06-05 09:22:43.000000000 +0000 @@ -1,15 +1,14 @@ module Configurate; module Provider # This provides a basic {#lookup} method for other providers to build - # upon. Childs are expected to define +lookup_path(path, *args)+ where - # +path+ will be passed an array of settings generated by splitting the - # called setting at the dots. The method should return nil if the setting + # upon. Childs are expected to define +lookup_path(path, *args)+. + # The method should return nil if the setting # wasn't found and {#lookup} will raise an {SettingNotFoundError} in that # case. class Base - def lookup(setting, *args) - result = lookup_path(setting.split("."), *args) + def lookup(*args) + result = lookup_path(*args) return result unless result.nil? - raise Configurate::SettingNotFoundError, "The setting #{setting} was not found" + raise Configurate::SettingNotFoundError, "The setting #{args.first} was not found" end end end; end diff -Nru ruby-configurate-0.0.2/lib/configurate/proxy.rb ruby-configurate-0.0.8/lib/configurate/proxy.rb --- ruby-configurate-0.0.2/lib/configurate/proxy.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/lib/configurate/proxy.rb 2013-06-05 09:22:43.000000000 +0000 @@ -1,76 +1,84 @@ module Configurate # Proxy object to support nested settings - # Cavehat: Since this is always true, adding a ? at the end + # + # *Cavehats*: Since this object is always true, adding a +?+ at the end # returns the value, if found, instead of the proxy object. # So instead of +if settings.foo.bar+ use +if settings.foo.bar?+ # to check for boolean values, +if settings.foo.bar.nil?+ to - # check for nil values, +if settings.foo.bar.present?+ to check for - # empty values if you're in Rails and call {#get} to actually return the value, - # commonly when doing +settings.foo.bar.get || 'default'+. If a setting - # ends with +=+ is too called directly, just like with +?+. + # check for nil values and of course you can do +if settings.foo.bar.present?+ to check for + # empty values if you're in Rails. Call {#get} to actually return the value, + # commonly when doing +settings.foo.bar.get || "default"+. Also don't + # use this in case statements since +Module#===+ can't be fooled, again + # call {#get}. + # + # If a setting ends with +=+ it's too called directly, just like with +?+. class Proxy < BasicObject - COMMON_KEY_NAMES = [:key, :method] - # @param lookup_chain [#lookup] - def initialize(lookup_chain) + def initialize lookup_chain @lookup_chain = lookup_chain - @setting = "" + @setting_path = SettingPath.new end def ! - !self.get - end - - def !=(other) - self.get != other + !target end - def ==(other) - self.get == other + [:!=, :==, :eql?].each do |method| + define_method method do |other| + target.public_send method, target_or_object(other) + end end def _proxy? true end - def respond_to?(method, include_private=false) - method == :_proxy? || self.get.respond_to?(method, include_private) + def respond_to? method, include_private=false + method == :_proxy? || target_respond_to?(method, include_private) end - def send(*args, &block) - self.__send__(*args, &block) + def send *args, &block + __send__(*args, &block) end + alias_method :public_send, :send - def method_missing(setting, *args, &block) - unless COMMON_KEY_NAMES.include? setting - target = self.get - if !(target.respond_to?(:_proxy?) && target._proxy?) && target.respond_to?(setting) - return target.send(setting, *args, &block) - end - end + def method_missing setting, *args, &block + return target.public_send(setting, *args, &block) if target_respond_to? setting - setting = setting.to_s - - self.append_setting(setting) + @setting_path << setting - return self.get(*args) if setting.end_with?("?") || setting.end_with?("=") + return target(*args) if @setting_path.is_question_or_setter? self end # Get the setting at the current path, if found. # (see LookupChain#lookup) - def get(*args) - setting = @setting[1..-1] - return unless setting - val = @lookup_chain.lookup(setting.chomp("?"), *args) - val + def target *args + return if @setting_path.empty? + + @lookup_chain.lookup @setting_path, *args end + alias_method :get, :target - protected - def append_setting(setting) - @setting << "." - @setting << setting + private + COMMON_KEY_NAMES = [:key, :method] + + def target_respond_to? setting, include_private=false + return false if COMMON_KEY_NAMES.include? setting + + value = target + return false if proxy? value + + value.respond_to? setting, include_private + end + + def proxy? obj + obj.respond_to?(:_proxy?) && obj._proxy? + end + + def target_or_object obj + proxy?(obj) ? obj.target : obj end end end diff -Nru ruby-configurate-0.0.2/lib/configurate/setting_path.rb ruby-configurate-0.0.8/lib/configurate/setting_path.rb --- ruby-configurate-0.0.2/lib/configurate/setting_path.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-configurate-0.0.8/lib/configurate/setting_path.rb 2013-06-05 09:22:43.000000000 +0000 @@ -0,0 +1,73 @@ +require 'forwardable' + +module Configurate + # Class encapsulating the concept of a path to a setting + class SettingPath + include Enumerable + extend Forwardable + + def initialize path=[] + path = path.split(".") if path.is_a? String + @path = path + end + + def initialize_copy original + super + @path = @path.clone + end + + def_delegators :@path, :empty?, :length, :size, :hsh + + # Whether the current path looks like a question or setter method + def is_question_or_setter? + is_question? || is_setter? + end + + # Whether the current path looks like a question method + def is_question? + @path.last.to_s.end_with?("?") + end + + # Whether the current path looks like a setter method + def is_setter? + @path.last.to_s.end_with?("=") + end + + def each + return to_enum(:each) unless block_given? + @path.each do |component| + yield clean_special_characters(component) + end + end + + [:join, :first, :last, :shift, :pop].each do |method| + define_method method do |*args| + clean_special_characters @path.public_send(method, *args) + end + end + + [:<<, :unshift, :push].each do |method| + define_method method do |*args| + @path.public_send method, *args.map(&:to_s) + end + end + + def to_s + join(".") + end + + def ==(other) + to_s == other.to_s + end + + def inspect + "" + end + + private + + def clean_special_characters value + value.to_s.chomp("?").chomp("=") + end + end +end diff -Nru ruby-configurate-0.0.2/lib/configurate.rb ruby-configurate-0.0.8/lib/configurate.rb --- ruby-configurate-0.0.2/lib/configurate.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/lib/configurate.rb 2013-06-05 09:22:43.000000000 +0000 @@ -1,4 +1,6 @@ +require 'forwardable' +require 'configurate/setting_path' require 'configurate/lookup_chain' require 'configurate/provider' require 'configurate/proxy' @@ -6,12 +8,12 @@ # A flexible and extendable configuration system. # The calling logic is isolated from the lookup logic -# through configuration providers, which only requirement +# through configuration providers, whose only requirement # is to define the +#lookup+ method and show a certain behavior on that. # The providers are asked in the order they were added until one provides # a response. This allows to even add multiple providers of the same type, # you never easier defined your default configuration parameters. -# There are no class methods used, you can have an unlimited amount of +# There is no shared state, you can have an unlimited amount of # independent configuration sources at the same time. # # See {Settings} for a quick start. @@ -19,7 +21,7 @@ # This is your main entry point. Instead of lengthy explanations # let an example demonstrate its usage: # - # require Rails.root.join('lib', 'configuration') + # require 'configuration_methods' # # AppSettings = Configurate::Settings.create do # add_provider Configurate::Provider::Env @@ -38,22 +40,28 @@ attr_reader :lookup_chain undef_method :method # Remove possible conflicts with common setting names + + extend Forwardable + + def initialize + @lookup_chain = LookupChain.new + $stderr.puts "Warning you called Configurate::Settings.new with a block, you really meant to call #create" if block_given? + end # @!method lookup(setting) - # (see LookupChain#lookup) + # (see {LookupChain#lookup}) + # @!method add_provider(provider, *args) - # (see LookupChain#add_provider) + # (see {LookupChain#add_provider}) + # @!method [](setting) - # (see LookupChain#[]) + # (see {LookupChain#[]}) + + def_delegators :@lookup_chain, :lookup, :add_provider, :[] + + # See description and {#lookup}, {#[]} and {#add_provider} def method_missing(method, *args, &block) - return @lookup_chain.send(method, *args, &block) if [:lookup, :add_provider, :[]].include?(method) - - Proxy.new(@lookup_chain).send(method, *args, &block) - end - - def initialize - @lookup_chain = LookupChain.new - $stderr.puts "Warning you called Configurate::Settings.new with a block, you really meant to call #create" if block_given? + Proxy.new(@lookup_chain).public_send(method, *args, &block) end # Create a new configuration object diff -Nru ruby-configurate-0.0.2/metadata.gz.asc ruby-configurate-0.0.8/metadata.gz.asc --- ruby-configurate-0.0.2/metadata.gz.asc 1970-01-01 00:00:00.000000000 +0000 +++ ruby-configurate-0.0.8/metadata.gz.asc 2013-06-05 09:22:43.000000000 +0000 @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.20 (GNU/Linux) + +iQEcBAABAgAGBQJRrlMbAAoJEPNH4OtHrHDWzAQH/jluldbgxLrHmdrfNGxDOfuy +frt0ZFgpUBkySAh6D16fJeDOu1ziPao8wHM+G4WpvC+szE0kgPoAQV68ON2x4zCL +FkidnZ0sKHe1z3VKWtl181Du+qbkdz8AhAigTtZPWd2BqR7wniKgvR5j31d553SX +bQI9ojwOwbOjREmQ795wn/xILE8jkh2tOu+GuMR6TTqY2xXOz3Ccjl+muCDPmnW2 +lQzwodaCVweEzR2AZrkK+MNI5Wq8Ox56RYh1DfHr7nk0jRDCnlSKBl0++EdV3Ies +eZ2gJBtPGRWk/bumqjaz60QS7m9BwUnq+HqkIQzrxlX/IeVY8cjZG8wyDkWwgxg= +=vOi8 +-----END PGP SIGNATURE----- diff -Nru ruby-configurate-0.0.2/metadata.yml ruby-configurate-0.0.8/metadata.yml --- ruby-configurate-0.0.2/metadata.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-configurate-0.0.8/metadata.yml 2013-06-05 09:22:43.000000000 +0000 @@ -0,0 +1,109 @@ +--- !ruby/object:Gem::Specification +name: configurate +version: !ruby/object:Gem::Version + version: 0.0.8 + prerelease: +platform: ruby +authors: +- Jonne Haß +autorequire: +bindir: bin +cert_chain: [] +date: 2013-06-04 00:00:00.000000000 Z +dependencies: +- !ruby/object:Gem::Dependency + name: rake + requirement: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: 10.0.3 + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: 10.0.3 +- !ruby/object:Gem::Dependency + name: rspec + requirement: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: 2.12.0 + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: 2.12.0 +description: Configurate is a flexible configuration system that can read settings + from multiple sources at the same time. +email: me@mrzyx.de +executables: [] +extensions: [] +extra_rdoc_files: [] +files: +- lib/configurate/provider/env.rb +- lib/configurate/provider/yaml.rb +- lib/configurate/provider/dynamic.rb +- lib/configurate/proxy.rb +- lib/configurate/lookup_chain.rb +- lib/configurate/provider.rb +- lib/configurate/setting_path.rb +- lib/configurate.rb +- README.md +- spec/configurate/provider_spec.rb +- spec/configurate/lookup_chain_spec.rb +- spec/configurate/provider/yaml_spec.rb +- spec/configurate/provider/env_spec.rb +- spec/configurate/provider/dynamic_spec.rb +- spec/configurate/setting_path_spec.rb +- spec/configurate/proxy_spec.rb +- spec/spec_helper.rb +- spec/configurate_spec.rb +homepage: http://mrzyx.github.com/configurate +licenses: +- MIT +post_install_message: +rdoc_options: [] +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: 1.9.2 +required_rubygems_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' + segments: + - 0 + hash: 61337675234892431 +requirements: [] +rubyforge_project: +rubygems_version: 1.8.25 +signing_key: +specification_version: 3 +summary: Flexbile configuration system +test_files: +- spec/configurate/provider_spec.rb +- spec/configurate/lookup_chain_spec.rb +- spec/configurate/provider/yaml_spec.rb +- spec/configurate/provider/env_spec.rb +- spec/configurate/provider/dynamic_spec.rb +- spec/configurate/setting_path_spec.rb +- spec/configurate/proxy_spec.rb +- spec/spec_helper.rb +- spec/configurate_spec.rb +has_rdoc: diff -Nru ruby-configurate-0.0.2/spec/configurate/lookup_chain_spec.rb ruby-configurate-0.0.8/spec/configurate/lookup_chain_spec.rb --- ruby-configurate-0.0.2/spec/configurate/lookup_chain_spec.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/spec/configurate/lookup_chain_spec.rb 2013-06-05 09:22:43.000000000 +0000 @@ -28,20 +28,40 @@ end describe "#lookup" do - before(:all) do + before do subject.add_provider ValidConfigurationProvider subject.add_provider ValidConfigurationProvider @provider = subject.instance_variable_get(:@provider) end it "it tries all providers" do - setting = "some.setting" + setting = Configurate::SettingPath.new "some.setting" + setting.stub(:clone).and_return(setting) @provider.each do |provider| provider.should_receive(:lookup).with(setting).and_raise(Configurate::SettingNotFoundError) end subject.lookup(setting) end + + it "converts a string to a SettingPath" do + provider = @provider.first + path = stub + path.stub(:clone).and_return(path) + provider.should_receive(:lookup).with(path).and_raise(Configurate::SettingNotFoundError) + setting = "bar" + Configurate::SettingPath.should_receive(:new).with(setting).and_return(path) + subject.lookup(setting) + end + + it "passes a copy of the SettingPath to the provider" do + provider = @provider.first + path = mock("path") + copy = stub("copy") + path.should_receive(:clone).at_least(:once).and_return(copy) + provider.should_receive(:lookup).with(copy).and_raise(Configurate::SettingNotFoundError) + subject.lookup(path) + end it "stops if a value is found" do @provider[0].should_receive(:lookup).and_return("something") @@ -58,6 +78,23 @@ @provider[0].stub(:lookup).and_return(false) subject.lookup("enable").should be_false end + + it "converts 'true' to true" do + @provider[0].stub(:lookup).and_return("true") + subject.lookup("enable").should be_true + end + + it "converts 'false' to false" do + @provider[0].stub(:lookup).and_return("false") + subject.lookup("enable").should be_false + end + + it "returns the value unchanged if it can't be converted" do + value = mock + value.stub(:respond_to?).with(:to_s).and_return(false) + @provider[0].stub(:lookup).and_return(value) + subject.lookup("enable").should == value + end it "returns nil if no value is found" do @provider.each { |p| p.stub(:lookup).and_raise(Configurate::SettingNotFoundError) } diff -Nru ruby-configurate-0.0.2/spec/configurate/provider/dynamic_spec.rb ruby-configurate-0.0.8/spec/configurate/provider/dynamic_spec.rb --- ruby-configurate-0.0.2/spec/configurate/provider/dynamic_spec.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/spec/configurate/provider/dynamic_spec.rb 2013-06-05 09:22:43.000000000 +0000 @@ -4,12 +4,12 @@ subject { described_class.new } describe "#lookup_path" do it "returns nil if the setting was never set" do - subject.lookup_path(["not_me"]).should be_nil + subject.lookup_path(Configurate::SettingPath.new(["not_me"])).should be_nil end it "remembers the setting if it ends with =" do - subject.lookup_path(["find_me", "later="], "there") - subject.lookup_path(["find_me", "later"]).should == "there" + subject.lookup_path(Configurate::SettingPath.new(["find_me", "later="]), "there") + subject.lookup_path(Configurate::SettingPath.new(["find_me", "later"])).should == "there" end it "calls .get on the argument if a proxy object is given" do @@ -17,7 +17,7 @@ proxy.stub(:respond_to?).and_return(true) proxy.stub(:_proxy?).and_return(true) proxy.should_receive(:get) - subject.lookup_path(["bla="], proxy) + subject.lookup_path(Configurate::SettingPath.new(["bla="]), proxy) end end end diff -Nru ruby-configurate-0.0.2/spec/configurate/provider/yaml_spec.rb ruby-configurate-0.0.8/spec/configurate/provider/yaml_spec.rb --- ruby-configurate-0.0.2/spec/configurate/provider/yaml_spec.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/spec/configurate/provider/yaml_spec.rb 2013-06-05 09:22:43.000000000 +0000 @@ -17,25 +17,34 @@ it "raises if the file is not found" do ::YAML.stub(:load_file).and_raise(Errno::ENOENT) expect { - described_class.new "foo" + silence_stderr do + described_class.new "foo" + end }.to raise_error Errno::ENOENT end context "with a namespace" do it "looks in the file for that namespace" do - namespace = "some" + namespace = "some.nested" ::YAML.stub(:load_file).and_return(settings) provider = described_class.new 'bla', namespace: namespace - provider.instance_variable_get(:@settings).should == settings[namespace] + provider.instance_variable_get(:@settings).should == settings['some']['nested'] end it "raises if the namespace isn't found" do ::YAML.stub(:load_file).and_return({}) expect { - described_class.new 'bla', namespace: "foo" + described_class.new 'bla', namespace: "bar" }.to raise_error ArgumentError end + + it "works with an empty namespace in the file" do + ::YAML.stub(:load_file).and_return({'foo' => {'bar' => nil}}) + expect { + described_class.new 'bla', namespace: "foo.bar" + }.to_not raise_error ArgumentError + end end context "with required set to false" do diff -Nru ruby-configurate-0.0.2/spec/configurate/provider_spec.rb ruby-configurate-0.0.8/spec/configurate/provider_spec.rb --- ruby-configurate-0.0.2/spec/configurate/provider_spec.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/spec/configurate/provider_spec.rb 2013-06-05 09:22:43.000000000 +0000 @@ -1,15 +1,16 @@ require 'spec_helper' describe Configurate::Provider::Base do - subject { described_class.new } describe "#lookup" do - it "calls #lookup_path with the setting as array" do - subject.should_receive(:lookup_path).with(["foo", "bar"]).and_return("something") - subject.lookup("foo.bar").should == "something" + subject { described_class.new } + it "calls #lookup_path" do + path = Configurate::SettingPath.new(["foo", "bar"]) + subject.should_receive(:lookup_path).with(path).and_return("something") + subject.lookup(path).should == "something" end it "raises SettingNotFoundError if the #lookup_path returns nil" do - subject.should_receive(:lookup_path).and_return(nil) + subject.stub(:lookup_path).and_return(nil) expect { subject.lookup("bla") }.to raise_error Configurate::SettingNotFoundError diff -Nru ruby-configurate-0.0.2/spec/configurate/proxy_spec.rb ruby-configurate-0.0.8/spec/configurate/proxy_spec.rb --- ruby-configurate-0.0.2/spec/configurate/proxy_spec.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/spec/configurate/proxy_spec.rb 2013-06-05 09:22:43.000000000 +0000 @@ -1,32 +1,64 @@ require 'spec_helper' describe Configurate::Proxy do - let(:lookup_chain) { mock } - before do - lookup_chain.stub(:lookup).and_return("something") + let(:lookup_chain) { mock(lookup: "something") } + let(:proxy) { described_class.new(lookup_chain) } + + describe "in case statements" do + it "acts like the target" do + pending "If anyone knows a way to overwrite ===, please tell me :P" + result = case proxy + when String + "string" + else + "wrong" + end + result.should == "string" + end end describe "#method_missing" do - it "calls #get if the method ends with a ?" do - lookup_chain.should_receive(:lookup).with("enable").and_return(false) - described_class.new(lookup_chain).method_missing(:enable?) + it "calls #target if the method ends with a ?" do + lookup_chain.should_receive(:lookup).and_return(false) + proxy.method_missing(:enable?) end - it "calls #get if the method ends with a =" do - lookup_chain.should_receive(:lookup).with("url=").and_return(false) - described_class.new(lookup_chain).method_missing(:url=) + it "calls #target if the method ends with a =" do + lookup_chain.should_receive(:lookup).and_return(false) + proxy.method_missing(:url=) + end + end + + describe "delegations" do + it "calls the target when negating" do + target = mock + lookup_chain.stub(:lookup).and_return(target) + target.should_receive(:!) + proxy.something.__send__(:!) + end + + it "enables sends even though be BasicObject" do + proxy.should_receive(:foo) + proxy.send(:foo) end end + + describe "#proxy" do + subject { proxy._proxy? } + it { should be_true } + end - describe "#get" do - [:to_str, :to_s, :to_xml, :respond_to?, :present?, :!=, + describe "#target" do + [:to_str, :to_s, :to_xml, :respond_to?, :present?, :!=, :eql?, :each, :try, :size, :length, :count, :==, :=~, :gsub, :blank?, :chop, :start_with?, :end_with?].each do |method| it "is called for accessing #{method} on the proxy" do target = mock - lookup_chain.should_receive(:lookup).and_return(target) + lookup_chain.stub(:lookup).and_return(target) + target.stub(:respond_to?).and_return(true) + target.stub(:_proxy?).and_return(false) target.should_receive(method).and_return("something") - described_class.new(lookup_chain).something.__send__(method, mock) + proxy.something.__send__(method, mock) end end @@ -35,22 +67,12 @@ target = mock lookup_chain.should_not_receive(:lookup) target.should_not_receive(method) - described_class.new(lookup_chain).something.__send__(method, mock) + proxy.something.__send__(method, mock) end end - it "strips leading dots" do - lookup_chain.should_receive(:lookup).with("foo.bar").and_return("something") - described_class.new(lookup_chain).foo.bar.get - end - it "returns nil if no setting is given" do - described_class.new(lookup_chain).get.should be_nil - end - - it "strips ? at the end" do - lookup_chain.should_receive(:lookup).with("foo.bar").and_return("something") - described_class.new(lookup_chain).foo.bar? + proxy.target.should be_nil end end end diff -Nru ruby-configurate-0.0.2/spec/configurate/setting_path_spec.rb ruby-configurate-0.0.8/spec/configurate/setting_path_spec.rb --- ruby-configurate-0.0.2/spec/configurate/setting_path_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-configurate-0.0.8/spec/configurate/setting_path_spec.rb 2013-06-05 09:22:43.000000000 +0000 @@ -0,0 +1,109 @@ +require 'spec_helper' + +describe Configurate::SettingPath do + let(:normal_path) { described_class.new([:foo]) } + let(:question_path) { described_class.new([:foo?]) } + let(:setter_path) { described_class.new([:foo=]) } + let(:long_path) { described_class.new(["foo", "bar?"]) } + + describe "#initialize" do + context "with a string" do + it "creates a path" do + described_class.new(long_path.to_s).should == long_path + end + end + end + + describe "#is_question?" do + context "with a question signature as setting" do + subject { question_path.is_question? } + it { should be_true } + end + + context "with a normal path as setting" do + subject { normal_path.is_question? } + it { should be_false } + end + end + + describe "#is_setter?" do + context "with a setter signature as setting" do + subject { setter_path.is_setter? } + it { should be_true } + end + + context "with a normal path as setting" do + subject { normal_path.is_setter? } + it { should be_false } + end + end + + describe "#initialize_copy" do + it "modifying a copy leaves the original unchanged" do + original = described_class.new ["foo", "bar"] + copy = original.clone + copy << "baz" + copy.should include "baz" + original.should_not include "baz" + end + end + + + describe "#is_question_or_setter?" do + context "with a question signature as setting" do + subject { question_path.is_question_or_setter? } + it { should be_true } + end + + context "with a setter signature as setting" do + subject { setter_path.is_question_or_setter? } + it { should be_true } + end + + context "with a normal path as setting" do + subject { normal_path.is_question_or_setter? } + it { should be_false } + end + end + + describe "#each" do + it "should strip special characters" do + long_path.all? { |c| c.include? "?" }.should be_false + end + end + + [:join, :first, :last, :shift, :pop].each do |method| + describe "##{method}" do + subject { question_path.public_send method } + it { should_not include "?" } + end + end + + [:<<, :unshift, :push].each do |method| + describe "##{method}" do + it 'converts the argument to a string' do + arg = mock + arg.should_receive(:to_s).and_return('bar') + described_class.new.public_send method, arg + end + end + end + + describe "#to_s" do + let(:path) { "example.path" } + subject { described_class.new(path.split(".")).to_s } + it { should == path } + + context "with a question signature as setting" do + subject { described_class.new("#{path}?".split(".")).to_s } + it { should == path } + end + end + + describe "#inspect" do + it "includes the dotted path" do + path = described_class.new([:foo, :bar]) + path.inspect.should include "foo.bar" + end + end +end diff -Nru ruby-configurate-0.0.2/spec/spec_helper.rb ruby-configurate-0.0.8/spec/spec_helper.rb --- ruby-configurate-0.0.2/spec/spec_helper.rb 2013-01-29 11:47:52.000000000 +0000 +++ ruby-configurate-0.0.8/spec/spec_helper.rb 2013-06-05 09:22:43.000000000 +0000 @@ -5,8 +5,20 @@ # # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration + +begin + require 'coveralls' + Coveralls.wear! +rescue LoadError; end + require 'configurate' +def silence_stderr + $stderr = StringIO.new + yield + $stderr = STDERR +end + RSpec.configure do |config| config.treat_symbols_as_metadata_keys_with_true_values = true config.run_all_when_everything_filtered = true