omniconf 0.0.1 → 0.0.2

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/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 1.9.2
3
4
  - 1.9.3
4
- - ruby-head
5
5
  - ree
data/README.md CHANGED
@@ -4,18 +4,21 @@ A _RubyGem_ that provides an application-agnostic configuration merger.
4
4
 
5
5
  # Setup
6
6
 
7
- Configure and load desired backends by creating a new initializer `config/initializers/omniconf.rb`:
7
+ Configure and load desired back-ends by creating a new initializer:
8
+
9
+ - With a Rails application, just run `rails g omniconf:install`.
10
+ - Without a Rails application, you need to create a file along these lines (see below):
8
11
 
9
12
  ```ruby
10
13
  Omniconf.setup do |config|
11
14
  config.sources = {
12
- :yaml_config => {
15
+ :yaml => {
13
16
  :type => :yaml,
14
17
  :file => "config/settings.yml"
15
18
  },
16
- :database_config => {
19
+ :database => {
17
20
  :type => :active_record,
18
- :model_name => :ConfigValue
21
+ :model => "ConfigValue"
19
22
  }
20
23
  }
21
24
  end
@@ -44,13 +47,13 @@ $ rails c
44
47
  ```ruby
45
48
  > Omniconf.configuration.some_config_from_database = "def" # updates value in DB using ConfigValue model
46
49
  => "def"
47
- > Omniconf.configuration.some_config_from_yaml = 456 # raises an exception because the value comes from YAML - who would want to update a YAML file?!
48
- => Omniconf::ReadOnlyConfigurationValue: cannot set 'some_config_from_yaml' because it belongs to a read-only back-end source (id: :yaml_config, type: Yaml)
50
+ > Omniconf.configuration.some_config_from_yaml = 456 # raises an exception because the value comes from YAML
51
+ => Omniconf::ReadOnlyConfigurationValue: cannot set 'some_config_from_yaml' because it belongs to a read-only back-end source (id: :yaml, type: Yaml)
49
52
  > Omniconf.configuration.api.username = "admin" # it works with nested values too
50
53
  => "admin"
51
54
  > Omniconf.configuration.brand_new_value = "whatever" # raises an exception because you've got to tell which back-end will store the new value
52
55
  => Omniconf::UnknownConfigurationValue: cannot set a configuration value with no parent
53
- > Omniconf.sources[:database_config].brand_new_value = "whatever" # adds a new row in ConfigValue model
56
+ > Omniconf.sources[:database].brand_new_value = "whatever" # adds a new record in ConfigValue model
54
57
  => "whatever"
55
58
  ```
56
59
 
@@ -61,15 +64,21 @@ Other parameters default to standard values for Rails.
61
64
 
62
65
  ### Yaml
63
66
 
64
- Nothing to configure apart from having a YAML file.
65
-
66
67
  _Note: read-only._
67
68
 
69
+ #### Parameters
70
+
71
+ - `:type => :yaml`
72
+ - `:file`: path to the YAML file to load (default: `config/settings.yml`)
73
+ - `:environment`: the root node to load from your YAML file (typically `development`, `production`, etc.)
74
+
68
75
  ### ActiveRecord
69
76
 
70
- Add `gem 'activerecord'` in your `Gemfile`.
77
+ #### Setup
71
78
 
72
- Create a new migration to add the config table: _(FIXME: add a rake task for this)_
79
+ - Add `gem 'activerecord'` in your `Gemfile`.
80
+ - With a Rails application, `rails g omniconf:install` has already created a migration for you.
81
+ - Without a Rails application, create a new migration to add the config table:
73
82
 
74
83
  ```ruby
75
84
  class CreateConfigValues < ActiveRecord::Migration
@@ -83,19 +92,20 @@ class CreateConfigValues < ActiveRecord::Migration
83
92
  end
84
93
  ```
85
94
 
86
- ### Redis
87
-
88
- Add `gem 'redis'` in your `Gemfile`.
95
+ #### Parameters
89
96
 
90
- Not yet implemented.
97
+ - `:type => :active_record`
98
+ - `:model`: name of the ActiveRecord model (default: `ConfigValue`)
99
+ - `:config_file`: path to the database settings (default: `config/database.yml`)
100
+ - `:environment`: environment to load (typically `development`, `production`, etc.)
91
101
 
92
102
  ## Reserved words
93
103
 
94
104
  /!\ You should not use these names as configuration keys:
95
105
 
96
- - `to_hash`: it's a helper which returns the configuration as a hash
106
+ - `to_hash`: returns the configuration as a hash
97
107
  - `inspect`: outputs sub-values as a hash
98
- - `get_or_default`: it's a helper which returns the value if it exists or creates it otherwise (usage: `get_or_default(key, default_value)`)
108
+ - `get_or_default`: returns the value if it exists or creates it otherwise (usage: `get_or_default(key, default_value)`)
99
109
  - `method_missing`: used internally
100
110
  - everything which starts with `__` (double underscore): used internally
101
111
 
@@ -103,7 +113,7 @@ Not yet implemented.
103
113
 
104
114
  `rake`
105
115
 
106
- Tested against _ree_, _ruby-1.9.3_ and _ruby-head_.
116
+ Tested against _ree_, _ruby-1.9.2_ and _ruby-1.9.3_ thanks to [Travis CI](http://travis-ci.org/#!/Picklive/omniconf "It rocks!").
107
117
 
108
118
  # License
109
119
 
@@ -6,7 +6,7 @@ module Omniconf
6
6
  def initialize id, params
7
7
  @source_id = id
8
8
  defaults = {
9
- :model_name => :ConfigValue
9
+ :model => 'ConfigValue'
10
10
  }
11
11
  defaults.merge!({
12
12
  :environment => Rails.env,
@@ -24,7 +24,7 @@ module Omniconf
24
24
  begin
25
25
  records = @model.all
26
26
  rescue ::ActiveRecord::StatementInvalid => e
27
- Omniconf.logger.warn "Could not load #{@params[:model_name]} model, ignoring this configuration source."
27
+ Omniconf.logger.warn "Could not load #{@params[:model]} model, ignoring this configuration source."
28
28
  return
29
29
  end
30
30
 
@@ -54,7 +54,7 @@ module Omniconf
54
54
 
55
55
  def setup
56
56
  # define the ActiveRecord model if missing
57
- unless Object.const_defined? @params[:model_name]
57
+ unless Object.const_defined? @params[:model]
58
58
  unless ::ActiveRecord::Base.connected?
59
59
  ::ActiveRecord::Base.configurations = YAML::load(IO.read(@params[:config_file]))
60
60
  ::ActiveRecord::Base.establish_connection(@params[:environment])
@@ -62,12 +62,13 @@ module Omniconf
62
62
 
63
63
  klass = Class.new ::ActiveRecord::Base do
64
64
  validates_uniqueness_of :key
65
+ serialize :value
65
66
  end
66
67
 
67
- Object.const_set @params[:model_name], klass
68
+ Object.const_set @params[:model], klass
68
69
  end
69
70
 
70
- @model ||= @params[:model_name].to_s.constantize
71
+ @model ||= @params[:model].constantize
71
72
  end
72
73
  end
73
74
  end
@@ -5,6 +5,7 @@ module Omniconf
5
5
  class Base
6
6
  attr_reader :source_id
7
7
  attr_reader :configuration
8
+ def reload_configuration!; load_configuration! end
8
9
  end
9
10
  end
10
11
  end
@@ -1,3 +1,4 @@
1
+ require 'yaml'
1
2
  require 'omniconf/adapters/read_only'
2
3
 
3
4
  module Omniconf
@@ -67,9 +67,14 @@ module Omniconf
67
67
  # add a catch-all exception
68
68
  # (more descriptive than "undefined method `xxx' for nil:NilClass")
69
69
  class << value
70
- def method_missing *args
71
- raise UnknownConfigurationValue,
72
- "cannot get a configuration value with no parent"
70
+ def method_missing method, *args
71
+ if method == :to_str
72
+ # need to raise NoMethodError here for Ruby 1.9.2 compatibility
73
+ raise NoMethodError, "undefined method `#{method}' for #{self}"
74
+ else
75
+ raise UnknownConfigurationValue,
76
+ "cannot get a configuration value with no parent"
77
+ end
73
78
  end
74
79
  end
75
80
  end
@@ -1,3 +1,3 @@
1
1
  module Omniconf
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/omniconf.rb CHANGED
@@ -22,11 +22,10 @@ module Omniconf
22
22
  end
23
23
 
24
24
  def logger
25
- unless @logger
26
- @logger = Logger.new(STDOUT)
27
- @logger.level = @settings.logger_level if @settings
28
- @logger.level = Logger::INFO if @logger.level.nil?
29
- end
25
+ return @logger ||= Rails.logger if defined? Rails
26
+
27
+ @logger ||= Logger.new(STDOUT)
28
+ @logger.level = @settings.logger_level || Logger::INFO
30
29
  @logger
31
30
  end
32
31
 
@@ -0,0 +1,29 @@
1
+ module Omniconf
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ desc "Installs Omniconf and generates the necessary migration"
5
+
6
+ include Rails::Generators::Migration
7
+
8
+ def self.source_root
9
+ File.expand_path("../templates", __FILE__)
10
+ end
11
+
12
+ def self.next_migration_number(dirname)
13
+ Time.now.strftime("%Y%m%d%H%M%S")
14
+ end
15
+
16
+ def copy_initializer
17
+ template 'omniconf.rb.erb', 'config/initializers/omniconf.rb'
18
+ end
19
+
20
+ def create_migrations
21
+ Dir["#{self.class.source_root}/migrations/*.rb"].sort.each do |filepath|
22
+ name = File.basename(filepath)
23
+ migration_template "migrations/#{name}", "db/migrate/#{name.gsub(/^\d+_/,'')}"
24
+ sleep 1 # ensure next migration gets a new number
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ class CreateConfigValues < ActiveRecord::Migration
2
+ def change
3
+ create_table :config_values do |t|
4
+ t.string :key, :null => false
5
+ t.string :value, :null => false
6
+ end
7
+ add_index :config_values, :key, :unique => true
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ Omniconf.setup do |config|
2
+ config.sources = {
3
+ :yaml => {
4
+ :type => :yaml,
5
+ :file => "config/settings.yml"
6
+ },
7
+ :database => {
8
+ :type => :active_record,
9
+ :model => "ConfigValue"
10
+ }
11
+ }
12
+ end
13
+
@@ -3,5 +3,8 @@ test:
3
3
  nested:
4
4
  yaml_key: nested_yaml_value
5
5
  overridden: by_yaml
6
+ some_integer: 1337
7
+ some_float: 3.14
8
+ some_array: [1, 2, 3]
6
9
  development:
7
10
  yaml_key: yaml_value_dev
@@ -4,7 +4,7 @@ require 'omniconf/adapters/active_record'
4
4
  describe Omniconf::Adapter::ActiveRecord do
5
5
  def load_configuration
6
6
  @adapter = Omniconf::Adapter::ActiveRecord.new(:active_record, {
7
- :model_name => :ConfigValue,
7
+ :model => 'ConfigValue',
8
8
  :environment => 'test',
9
9
  :config_file => File.expand_path(
10
10
  '../../../fixtures/omniconf/adapters/active_record/config/database.yml',
@@ -21,54 +21,67 @@ describe Omniconf::Adapter::ActiveRecord do
21
21
  end
22
22
 
23
23
  describe "#configuration" do
24
+ def config
25
+ @adapter.configuration
26
+ end
27
+
24
28
  before do
25
29
  Omniconf.stub(:merge_configuration!)
26
30
  load_configuration
27
31
  end
28
32
 
29
- let(:configuration) { @adapter.configuration }
30
-
31
33
  describe "getting values" do
32
34
  it "returns a value" do
33
- configuration.ar_key.should == 'ar_value'
35
+ config.ar_key.should == 'ar_value'
34
36
  end
35
37
 
36
38
  it "returns a nested value" do
37
- configuration.nested.ar_key.should == 'nested_ar_value'
39
+ config.nested.ar_key.should == 'nested_ar_value'
38
40
  end
39
41
  end
40
42
 
41
43
  describe "setting values" do
42
- it "updates configuration values into database" do
43
- configuration.ar_key.should == 'ar_value'
44
- configuration.ar_key = 'new_ar_value'
45
- configuration.ar_key.should == 'new_ar_value'
44
+ it "updates config values into database" do
45
+ config.ar_key.should == 'ar_value'
46
+ config.ar_key = 'new_ar_value'
47
+ config.ar_key.should == 'new_ar_value'
46
48
  end
47
49
 
48
- it "creates configuration values into database" do
49
- configuration.new_ar_key.should be_nil
50
- configuration.new_ar_key = 'new_ar_value'
51
- configuration.new_ar_key.should == 'new_ar_value'
50
+ it "creates config values into database" do
51
+ config.new_ar_key.should be_nil
52
+ config.new_ar_key = 'new_ar_value'
53
+ config.new_ar_key.should == 'new_ar_value'
52
54
  end
53
-
54
- it "it doesn't cast values to String" # TODO serialize them and keep type
55
55
  end
56
56
 
57
57
  describe "#get_or_default" do
58
58
  it "creates a new default value" do
59
- configuration.newValue.should be_nil
59
+ config.newValue.should be_nil
60
60
  @adapter.should_receive(:set_value).with(['newValue'], 'a')
61
- configuration.get_or_default('newValue', 'a').should == 'a'
62
- configuration.get_or_default('newValue', 'b').should == 'a'
61
+ config.get_or_default('newValue', 'a').should == 'a'
62
+ config.get_or_default('newValue', 'b').should == 'a'
63
63
  end
64
64
 
65
65
  it "creates a new default nested value" do
66
- configuration.nested.newValue.should be_nil
66
+ config.nested.newValue.should be_nil
67
67
  @adapter.should_receive(:set_value).with(['nested', 'newValue'], 'a')
68
- configuration.nested.get_or_default('newValue', 'a').should == 'a'
69
- configuration.nested.get_or_default('newValue', 'b').should == 'a'
68
+ config.nested.get_or_default('newValue', 'a').should == 'a'
69
+ config.nested.get_or_default('newValue', 'b').should == 'a'
70
70
  end
71
71
  end
72
+
73
+ it "keeps value types" do
74
+ config.some_integer.should be_nil
75
+ config.some_float.should be_nil
76
+ config.some_array.should be_nil
77
+ config.some_integer = 1337
78
+ config.some_float = 3.14
79
+ config.some_array = [1, 2, 3]
80
+ @adapter.reload_configuration!
81
+ config.some_integer.should == 1337
82
+ config.some_float.should == 3.14
83
+ config.some_array.should == [1, 2, 3]
84
+ end
72
85
  end
73
86
  end
74
87
 
@@ -12,75 +12,84 @@ describe Omniconf::Adapter::Yaml do
12
12
  @adapter.load_configuration!
13
13
  end
14
14
 
15
+
15
16
  describe "#configuration" do
17
+ def config
18
+ @adapter.configuration
19
+ end
20
+
16
21
  before do
17
22
  Omniconf.stub(:merge_configuration!)
18
23
  load_configuration('test')
19
24
  end
20
25
 
21
- let(:configuration) { @adapter.configuration }
22
-
23
26
  describe "getting values" do
24
27
  it "returns a value" do
25
- configuration.yaml_key.should == 'yaml_value'
28
+ config.yaml_key.should == 'yaml_value'
26
29
  end
27
30
 
28
31
  it "returns a nested value" do
29
- configuration.nested.yaml_key.should == 'nested_yaml_value'
32
+ config.nested.yaml_key.should == 'nested_yaml_value'
30
33
  end
31
34
  end
32
35
 
33
36
  describe "setting values" do
34
37
  it "fails to update a value" do
35
- configuration.yaml_key.should_not be_nil
38
+ config.yaml_key.should_not be_nil
36
39
  expect {
37
- configuration.yaml_key = 'whatever'
40
+ config.yaml_key = 'whatever'
38
41
  }.to raise_error Omniconf::ReadOnlyConfigurationValue
39
42
  end
40
43
 
41
44
  it "fails to update a nested value" do
42
- configuration.nested.yaml_key.should_not be_nil
45
+ config.nested.yaml_key.should_not be_nil
43
46
  expect {
44
- configuration.nested.yaml_key = 'whatever'
47
+ config.nested.yaml_key = 'whatever'
45
48
  }.to raise_error Omniconf::ReadOnlyConfigurationValue
46
49
  end
47
50
 
48
51
  it "fails to create a value" do
49
- configuration.new_yaml_key.should be_nil
52
+ config.new_yaml_key.should be_nil
50
53
  expect {
51
- configuration.new_yaml_key = 'whatever'
54
+ config.new_yaml_key = 'whatever'
52
55
  }.to raise_error Omniconf::ReadOnlyConfigurationValue
53
56
  end
54
57
 
55
58
  it "fails to create a nested value" do
56
- configuration.nested.new_yaml_key.should be_nil
59
+ config.nested.new_yaml_key.should be_nil
57
60
  expect {
58
- configuration.nested.new_yaml_key = 'whatever'
61
+ config.nested.new_yaml_key = 'whatever'
59
62
  }.to raise_error Omniconf::ReadOnlyConfigurationValue
60
63
  end
61
64
  end
62
65
 
63
66
  describe "#get_or_default" do
64
67
  it "fails to create a new default value" do
65
- configuration.newValue.should be_nil
68
+ config.newValue.should be_nil
66
69
  expect {
67
- configuration.get_or_default('newValue', 'a').should == 'a'
70
+ config.get_or_default('newValue', 'a').should == 'a'
68
71
  }.to raise_error Omniconf::ReadOnlyConfigurationValue
69
- configuration.newValue.should be_nil
72
+ config.newValue.should be_nil
70
73
  end
71
74
 
72
75
  it "fails to create a new nested default value" do
73
- configuration.nested.newValue.should be_nil
76
+ config.nested.newValue.should be_nil
74
77
  expect {
75
- configuration.nested.get_or_default('newValue', 'a').should == 'a'
78
+ config.nested.get_or_default('newValue', 'a').should == 'a'
76
79
  }.to raise_error Omniconf::ReadOnlyConfigurationValue
77
- configuration.nested.newValue.should be_nil
80
+ config.nested.newValue.should be_nil
78
81
  end
79
82
  end
80
83
 
81
84
  it "loads the right environment" do
82
85
  load_configuration 'development'
83
- configuration.yaml_key.should == 'yaml_value_dev'
86
+ config.yaml_key.should == 'yaml_value_dev'
87
+ end
88
+
89
+ it "keeps value types" do
90
+ config.some_integer.should == 1337
91
+ config.some_float.should == 3.14
92
+ config.some_array.should == [1, 2, 3]
84
93
  end
85
94
  end
86
95
  end
@@ -30,7 +30,7 @@ describe Omniconf do
30
30
  },
31
31
  :database => {
32
32
  :type => :active_record,
33
- :model_name => :ConfigValue,
33
+ :model => 'ConfigValue',
34
34
  :environment => 'test',
35
35
  :config_file => File.expand_path(
36
36
  '../fixtures/omniconf/adapters/active_record/config/database.yml',
@@ -49,7 +49,9 @@ describe Omniconf do
49
49
  end
50
50
 
51
51
  describe "#configuration" do
52
- let(:config) { Omniconf.configuration }
52
+ def config
53
+ Omniconf.configuration
54
+ end
53
55
 
54
56
  it "returns an instance of Omniconf::Configuration" do
55
57
  config.should be_an_instance_of Omniconf::Configuration
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniconf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-08 00:00:00.000000000 Z
12
+ date: 2012-02-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &2156203800 !ruby/object:Gem::Requirement
16
+ requirement: &2152356800 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0.9'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2156203800
24
+ version_requirements: *2152356800
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &2156201760 !ruby/object:Gem::Requirement
27
+ requirement: &2152342400 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '2.8'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2156201760
35
+ version_requirements: *2152342400
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sqlite3
38
- requirement: &2156200400 !ruby/object:Gem::Requirement
38
+ requirement: &2152340720 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '1.3'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2156200400
46
+ version_requirements: *2152340720
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: activerecord
49
- requirement: &2156199340 !ruby/object:Gem::Requirement
49
+ requirement: &2152339860 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '3.2'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2156199340
57
+ version_requirements: *2152339860
58
58
  description: Merge configurations from multiple back-ends for easy use in a complex
59
59
  application.
60
60
  email:
@@ -82,6 +82,9 @@ files:
82
82
  - lib/omniconf/helpers.rb
83
83
  - lib/omniconf/settings.rb
84
84
  - lib/omniconf/version.rb
85
+ - lib/rails/generators/omniconf/install/install_generator.rb
86
+ - lib/rails/generators/omniconf/install/templates/migrations/1_create_config_values.rb
87
+ - lib/rails/generators/omniconf/install/templates/omniconf.rb.erb
85
88
  - omniconf.gemspec
86
89
  - spec/fixtures/omniconf/adapters/active_record/config/database.yml
87
90
  - spec/fixtures/omniconf/adapters/active_record/db/schema.rb
@@ -112,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
115
  version: '0'
113
116
  requirements: []
114
117
  rubyforge_project: omniconf
115
- rubygems_version: 1.8.11
118
+ rubygems_version: 1.8.10
116
119
  signing_key:
117
120
  specification_version: 3
118
121
  summary: Merge multiple configuration sources into one.