pax_global_header00006660000000000000000000000064121536015430014512gustar00rootroot0000000000000052 comment=9a72b327d7c7769585add3b3974701be7a8db4c1 ruby-configurate-0.0.8/000077500000000000000000000000001215360154300150045ustar00rootroot00000000000000ruby-configurate-0.0.8/README.md000066400000000000000000000142731215360154300162720ustar00rootroot00000000000000# 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/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) 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 ```ruby puts "yep" if Config.enable_stuff ``` always outputs `yep`. The workaround is to append `.get` or `?` to get the real value: ```ruby puts "yep" if Config.enable_stuff? ``` ### 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) ruby-configurate-0.0.8/data.tar.gz.asc000066400000000000000000000007521215360154300176150ustar00rootroot00000000000000-----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----- ruby-configurate-0.0.8/lib/000077500000000000000000000000001215360154300155525ustar00rootroot00000000000000ruby-configurate-0.0.8/lib/configurate.rb000066400000000000000000000050151215360154300204060ustar00rootroot00000000000000require 'forwardable' require 'configurate/setting_path' require 'configurate/lookup_chain' require 'configurate/provider' require 'configurate/proxy' # A flexible and extendable configuration system. # The calling logic is isolated from the lookup logic # 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 is no shared state, you can have an unlimited amount of # independent configuration sources at the same time. # # See {Settings} for a quick start. module Configurate # This is your main entry point. Instead of lengthy explanations # let an example demonstrate its usage: # # require 'configuration_methods' # # AppSettings = 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' # # extend YourConfigurationMethods # end # # AppSettings.setup_something if AppSettings.something.enable? # # Please also read the note at {Proxy}! class Settings 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}) # @!method add_provider(provider, *args) # (see {LookupChain#add_provider}) # @!method [](setting) # (see {LookupChain#[]}) def_delegators :@lookup_chain, :lookup, :add_provider, :[] # See description and {#lookup}, {#[]} and {#add_provider} def method_missing(method, *args, &block) Proxy.new(@lookup_chain).public_send(method, *args, &block) end # Create a new configuration object # @yield the given block will be evaluated in the context of the new object def self.create(&block) config = self.new config.instance_eval(&block) if block_given? config end end class SettingNotFoundError < RuntimeError; end end ruby-configurate-0.0.8/lib/configurate/000077500000000000000000000000001215360154300200605ustar00rootroot00000000000000ruby-configurate-0.0.8/lib/configurate/lookup_chain.rb000066400000000000000000000037351215360154300230700ustar00rootroot00000000000000module Configurate # This object builds a chain of configuration providers to try to find # the value of a setting. class LookupChain def initialize @provider = [] end # Adds a provider to the chain. Providers are tried in the order # they are added, so the order is important. # # @param provider [#lookup] # @param *args the arguments passed to the providers constructor # @raise [ArgumentError] if an invalid provider is given # @return [void] def add_provider(provider, *args) unless provider.respond_to?(:instance_methods) && provider.instance_methods.include?(:lookup) raise ArgumentError, "the given provider does not respond to lookup" end @provider << provider.new(*args) end # Tries all providers in the order they were added to provide a response # for setting. # # @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 = SettingPath.new setting if setting.is_a? String @provider.each do |provider| begin return special_value_or_string(provider.lookup(setting.clone, *args)) rescue SettingNotFoundError; end end nil end alias_method :[], :lookup private def special_value_or_string(value) if [TrueClass, FalseClass, NilClass, Array, Hash].include?(value.class) return value elsif value.is_a?(String) return case value.strip when "true" then true when "false" then false when "", "nil" then nil else value end elsif value.respond_to?(:to_s) return value.to_s else return value end end end end ruby-configurate-0.0.8/lib/configurate/provider.rb000066400000000000000000000012011215360154300222310ustar00rootroot00000000000000module Configurate; module Provider # This provides a basic {#lookup} method for other providers to build # 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(*args) result = lookup_path(*args) return result unless result.nil? raise Configurate::SettingNotFoundError, "The setting #{args.first} was not found" end end end; end require 'configurate/provider/yaml' require 'configurate/provider/env' require 'configurate/provider/dynamic' ruby-configurate-0.0.8/lib/configurate/provider/000077500000000000000000000000001215360154300217125ustar00rootroot00000000000000ruby-configurate-0.0.8/lib/configurate/provider/dynamic.rb000066400000000000000000000012531215360154300236640ustar00rootroot00000000000000module Configurate; module Provider # This provider knows nothing upon initialization, however if you access # a setting ending with +=+ and give one argument to that call it remembers # that setting, stripping the +=+ and will return it on the next call # without +=+. class Dynamic < Base def initialize @settings = {} end def lookup_path(setting_path, *args) key = setting_path.to_s if setting_path.is_setter? && args.length > 0 value = args.first value = value.get if value.respond_to?(:_proxy?) && value._proxy? @settings[key] = value end @settings[key] end end end; end ruby-configurate-0.0.8/lib/configurate/provider/env.rb000066400000000000000000000011611215360154300230260ustar00rootroot00000000000000module 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+, 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(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 end; end ruby-configurate-0.0.8/lib/configurate/provider/yaml.rb000066400000000000000000000031701215360154300232020ustar00rootroot00000000000000require 'yaml' module Configurate; module Provider # 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 # @param opts [Hash] # @option opts [String] :namespace optionally set this as the root # @option opts [Boolean] :required wheter or not to raise an error if # the file or the namespace, if given, is not found. Defaults to +true+. # @raise [ArgumentError] if the namespace isn't found in the file # @raise [Errno:ENOENT] if the file isn't found def initialize(file, opts = {}) @settings = {} required = opts.delete(:required) { true } @settings = ::YAML.load_file(file) namespace = opts.delete(:namespace) unless namespace.nil? @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" raise e if required end def lookup_path(setting_path, *) lookup_in_hash(setting_path, @settings) end private 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 ruby-configurate-0.0.8/lib/configurate/proxy.rb000066400000000000000000000044631215360154300215750ustar00rootroot00000000000000module Configurate # Proxy object to support nested settings # # *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 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 # @param lookup_chain [#lookup] def initialize lookup_chain @lookup_chain = lookup_chain @setting_path = SettingPath.new end def ! !target end [:!=, :==, :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? || target_respond_to?(method, include_private) end def send *args, &block __send__(*args, &block) end alias_method :public_send, :send def method_missing setting, *args, &block return target.public_send(setting, *args, &block) if target_respond_to? setting @setting_path << setting 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 target *args return if @setting_path.empty? @lookup_chain.lookup @setting_path, *args end alias_method :get, :target 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 ruby-configurate-0.0.8/lib/configurate/setting_path.rb000066400000000000000000000031671215360154300231050ustar00rootroot00000000000000require '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 ruby-configurate-0.0.8/metadata.gz.asc000066400000000000000000000007521215360154300176770ustar00rootroot00000000000000-----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----- ruby-configurate-0.0.8/metadata.yml000066400000000000000000000053641215360154300173170ustar00rootroot00000000000000--- !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: ruby-configurate-0.0.8/spec/000077500000000000000000000000001215360154300157365ustar00rootroot00000000000000ruby-configurate-0.0.8/spec/configurate/000077500000000000000000000000001215360154300202445ustar00rootroot00000000000000ruby-configurate-0.0.8/spec/configurate/lookup_chain_spec.rb000066400000000000000000000063451215360154300242660ustar00rootroot00000000000000require 'spec_helper' class InvalidConfigurationProvider; end class ValidConfigurationProvider def lookup(setting, *args); end end describe Configurate::LookupChain do subject { described_class.new } describe "#add_provider" do it "adds a valid provider" do expect { subject.add_provider ValidConfigurationProvider }.to change { subject.instance_variable_get(:@provider).size }.by 1 end it "doesn't add an invalid provider" do expect { subject.add_provider InvalidConfigurationProvider }.to raise_error ArgumentError end it "passes extra args to the provider" do ValidConfigurationProvider.should_receive(:new).with(:extra) subject.add_provider ValidConfigurationProvider, :extra end end describe "#lookup" 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 = 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") @provider[1].should_not_receive(:lookup) subject.lookup("bla") end it "converts numbers to strings" do @provider[0].stub(:lookup).and_return(5) subject.lookup("foo").should == "5" end it "does not convert false to a string" do @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) } subject.lookup("not.me").should be_nil end end end ruby-configurate-0.0.8/spec/configurate/provider/000077500000000000000000000000001215360154300220765ustar00rootroot00000000000000ruby-configurate-0.0.8/spec/configurate/provider/dynamic_spec.rb000066400000000000000000000014731215360154300250660ustar00rootroot00000000000000require 'spec_helper' describe Configurate::Provider::Dynamic do subject { described_class.new } describe "#lookup_path" do it "returns nil if the setting was never set" do subject.lookup_path(Configurate::SettingPath.new(["not_me"])).should be_nil end it "remembers the setting if it ends with =" do 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 proxy = mock proxy.stub(:respond_to?).and_return(true) proxy.stub(:_proxy?).and_return(true) proxy.should_receive(:get) subject.lookup_path(Configurate::SettingPath.new(["bla="]), proxy) end end end ruby-configurate-0.0.8/spec/configurate/provider/env_spec.rb000066400000000000000000000020141215360154300242220ustar00rootroot00000000000000require 'spec_helper' describe Configurate::Provider::Env do subject { described_class.new } let(:existing_path) { ['existing', 'setting']} let(:not_existing_path) { ['not', 'existing', 'path']} let(:array_path) { ['array'] } before(:all) do ENV['EXISTING_SETTING'] = "there" ENV['ARRAY'] = "foo,bar,baz" end after(:all) do ENV['EXISTING_SETTING'] = nil ENV['ARRAY'] = nil end describe '#lookup_path' do it "joins and upcases the path" do ENV.should_receive(:[]).with("EXISTING_SETTING") subject.lookup_path(existing_path) end it "returns nil if the setting isn't available" do subject.lookup_path(not_existing_path).should be_nil end it "makes an array out of comma separated values" do subject.lookup_path(array_path).should == ["foo", "bar", "baz"] end it "returns a unfrozen string" do expect { setting = subject.lookup_path(existing_path) setting << "foo" }.to_not raise_error end end end ruby-configurate-0.0.8/spec/configurate/provider/yaml_spec.rb000066400000000000000000000046751215360154300244130ustar00rootroot00000000000000require 'spec_helper' describe Configurate::Provider::YAML do let(:settings) { {"toplevel" => "bar", "some" => { "nested" => { "some" => "lala", "setting" => "foo"} } } } describe "#initialize" do it "loads the file" do file = "foobar.yml" ::YAML.should_receive(:load_file).with(file).and_return({}) described_class.new file end it "raises if the file is not found" do ::YAML.stub(:load_file).and_raise(Errno::ENOENT) expect { 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.nested" ::YAML.stub(:load_file).and_return(settings) provider = described_class.new 'bla', namespace: 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: "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 it "doesn't raise if a file isn't found" do ::YAML.stub(:load_file).and_raise(Errno::ENOENT) expect { described_class.new "not_me", required: false }.not_to raise_error Errno::ENOENT end it "doesn't raise if a namespace isn't found" do ::YAML.stub(:load_file).and_return({}) expect { described_class.new 'bla', namespace: "foo", required: false }.not_to raise_error ArgumentError end end end describe "#lookup_path" do before do ::YAML.stub(:load_file).and_return(settings) @provider = described_class.new 'dummy' end it "looks up the whole nesting" do @provider.lookup_path(["some", "nested", "some"]).should == settings["some"]["nested"]["some"] end it "returns nil if no setting is found" do @provider.lookup_path(["not_me"]).should be_nil end end end ruby-configurate-0.0.8/spec/configurate/provider_spec.rb000066400000000000000000000011211215360154300234300ustar00rootroot00000000000000require 'spec_helper' describe Configurate::Provider::Base do describe "#lookup" do 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.stub(:lookup_path).and_return(nil) expect { subject.lookup("bla") }.to raise_error Configurate::SettingNotFoundError end end end ruby-configurate-0.0.8/spec/configurate/proxy_spec.rb000066400000000000000000000043311215360154300227650ustar00rootroot00000000000000require 'spec_helper' describe Configurate::Proxy do 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 #target if the method ends with a ?" do lookup_chain.should_receive(:lookup).and_return(false) proxy.method_missing(:enable?) end 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 "#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.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") proxy.something.__send__(method, mock) end end described_class::COMMON_KEY_NAMES.each do |method| it "is not called for accessing #{method} on the proxy" do target = mock lookup_chain.should_not_receive(:lookup) target.should_not_receive(method) proxy.something.__send__(method, mock) end end it "returns nil if no setting is given" do proxy.target.should be_nil end end end ruby-configurate-0.0.8/spec/configurate/setting_path_spec.rb000066400000000000000000000054671215360154300243100ustar00rootroot00000000000000require '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 ruby-configurate-0.0.8/spec/configurate_spec.rb000066400000000000000000000012471215360154300216070ustar00rootroot00000000000000require 'spec_helper' describe Configurate::Settings do describe "#method_missing" do subject { described_class.create } it "delegates the call to a new proxy object" do proxy = mock Configurate::Proxy.should_receive(:new).and_return(proxy) proxy.should_receive(:method_missing).with(:some_setting).and_return("foo") subject.some_setting end end [:lookup, :add_provider, :[]].each do |method| describe "#{method}" do subject { described_class.create } it "delegates the call to #lookup_chain" do subject.lookup_chain.should_receive(method) subject.send(method) end end end end ruby-configurate-0.0.8/spec/spec_helper.rb000066400000000000000000000016101215360154300205520ustar00rootroot00000000000000# This file was generated by the `rspec --init` command. Conventionally, all # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. # Require this file using `require "spec_helper"` to ensure that it is only # loaded once. # # 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 config.filter_run :focus # Run specs in random order to surface order dependencies. If you find an # order dependency and want to debug it, you can fix the order by providing # the seed, which is printed after each run. # --seed 1234 config.order = 'random' end