confection 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.ruby CHANGED
@@ -47,7 +47,7 @@ revision: 0
47
47
  created: '2011-11-06'
48
48
  summary: Multi-tenant configuration for Ruby
49
49
  title: Confection
50
- version: 0.2.0
50
+ version: 0.2.1
51
51
  name: confection
52
52
  description: Confection is a multi-tenant configuration system for Ruby projects.
53
53
  organization: Rubyworks
data/Confile.rb ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # QED test coverage report using SimpleCov.
5
+ #
6
+ # coverage_folder - the directory in which to store coverage report
7
+ # this defaults to `log/coverage`.
8
+ #
9
+ config :qed, :cov do
10
+ require 'simplecov'
11
+
12
+ dir = $properties.coverage_folder
13
+
14
+ SimpleCov.start do
15
+ coverage_dir(dir || 'log/coverage')
16
+ #add_group "Label", "lib/qed/directory"
17
+ end
18
+ end
19
+
20
+ #
21
+ # Example configuration.
22
+ #
23
+ config :example do
24
+ puts "Configuration Example!"
25
+ end
26
+
27
+ #
28
+ # Detroit assembly.
29
+ #
30
+ config :detroit do
31
+ email do
32
+ mailto 'ruby-talk@ruby-lang.org', 'rubyworks-mailinglist@googlegroups.com'
33
+ end
34
+
35
+ gem do
36
+ active true
37
+ end
38
+
39
+ github do
40
+ folder 'web'
41
+ end
42
+
43
+ dnote do
44
+ title 'Source Notes'
45
+ output 'log/notes.html'
46
+ end
47
+
48
+ locat do
49
+ output 'log/locat.html'
50
+ end
51
+
52
+ vclog do
53
+ output 'log/history.html',
54
+ 'log/changes.html'
55
+ end
56
+ end
57
+
@@ -0,0 +1,14 @@
1
+ # All core extensions come from Ruby Facets to maintain high standard for
2
+ # careful core extensions.
3
+
4
+ require 'facets/string/tabto'
5
+ require 'facets/to_hash'
6
+
7
+ #require 'facets/ostruct/to_h' # TODO: Newer version of facets.
8
+ require 'ostruct'
9
+ class OpenStruct
10
+ def to_h
11
+ @table.dup
12
+ end
13
+ end
14
+
@@ -0,0 +1,79 @@
1
+ module Confection
2
+
3
+ #
4
+ # Global properties is set for parsing project configuration.
5
+ # It is *always* the properties of the current project.
6
+ #
7
+ $properties = nil
8
+
9
+ # Current mixin extends the Confection module. Primarily is provides
10
+ # class methods for working with the current project's configurations.
11
+ #
12
+ module Current
13
+
14
+ #
15
+ def controller(scope, tool, *options)
16
+ params = (Hash === options.last ? options.pop : {})
17
+ params[:profile] = options.shift unless options.empty?
18
+
19
+ if from = params[:from]
20
+ projects[from] ||= Project.load(from)
21
+ projects[from].controller(scope, tool, params)
22
+ else
23
+ bootstrap if $properties.nil? # TODO: better way to go about this?
24
+ current_project.controller(scope, tool, params)
25
+ end
26
+ end
27
+
28
+ #
29
+ def bootstrap
30
+ $properties = current_project.properties
31
+ end
32
+
33
+ #
34
+ def projects
35
+ @projects ||= {}
36
+ end
37
+
38
+ #
39
+ def current_directory
40
+ @current_directory ||= Dir.pwd
41
+ end
42
+
43
+ #
44
+ def current_project
45
+ projects[current_directory] ||= Project.lookup(current_directory)
46
+ end
47
+
48
+ #
49
+ def clear!
50
+ current_project.store.clear!
51
+ end
52
+
53
+ #
54
+ def profiles(tool)
55
+ current_project.profiles(tool)
56
+ end
57
+
58
+ #
59
+ def each(&block)
60
+ current_project.each(&block)
61
+ end
62
+
63
+ #
64
+ def size
65
+ current_project.size
66
+ end
67
+
68
+ #
69
+ # Project properties.
70
+ #
71
+ def properties
72
+ current_project.properties
73
+ end
74
+
75
+ end
76
+
77
+ extend Current
78
+
79
+ end
@@ -0,0 +1,48 @@
1
+ module Confection
2
+
3
+ # HashBuilder takes a procedure and builds a Hash out of it.
4
+ #
5
+ # The procedure must conform to a set of rules to be useful in this respect.
6
+ # They must either take an argument and use that argument to set values, or
7
+ # if no argument is taken then `#instance_eval` is used to evaluate the
8
+ # procedure such that each method represents a key.
9
+ #
10
+ class HashBuilder < BasicObject
11
+
12
+ #
13
+ def initialize(hash={}, &block)
14
+ @hash = hash
15
+ case block.arity
16
+ when 0
17
+ instance_eval(&block)
18
+ else
19
+ block.call(self)
20
+ end
21
+ end
22
+
23
+ #
24
+ def to_h
25
+ @hash
26
+ end
27
+
28
+ #
29
+ def method_missing(s, *a, &b)
30
+ m = s.to_s
31
+ if a.empty? && !b
32
+ @hash[m.to_sym]
33
+ else
34
+ if b
35
+ @hash[m.chomp('=').to_sym] = HashBuilder.new(&b).to_h
36
+ else
37
+ if a.size > 1
38
+ @hash[m.chomp('=').to_sym] = a
39
+ else
40
+ @hash[m.chomp('=').to_sym] = a.first
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,161 @@
1
+ module Confection
2
+
3
+ # Project configuration.
4
+ #
5
+ # @todo Rename to `ProjectConfig` or ?
6
+ #
7
+ class Project
8
+
9
+ include Enumerable
10
+
11
+ #
12
+ # Configuration file pattern.
13
+ #
14
+ PATTERN = '{.,}confile{.rb,}'
15
+
16
+ #
17
+ # Per library cache.
18
+ #
19
+ def self.cache
20
+ @cache ||= {}
21
+ end
22
+
23
+ #
24
+ # Get project configuration from another library.
25
+ #
26
+ # This method uses the Finder gem.
27
+ #
28
+ # @param [String] lib
29
+ # Library name.
30
+ #
31
+ # @return [Project,nil] Located project.
32
+ #
33
+ def self.load(lib=nil)
34
+ if lib
35
+ lib = lib.to_s
36
+ return cache[lib] if cache.key?(lib)
37
+ cache[lib] ||= (
38
+ config_path = Find.path(PATTERN, :from=>lib).first
39
+ config_path ? new(File.dirname(config_path)) : nil
40
+ )
41
+ else
42
+ lookup
43
+ end
44
+ end
45
+
46
+ #
47
+ # Lookup configuation file.
48
+ #
49
+ # @param dir [String]
50
+ # Optional directory to begin search.
51
+ #
52
+ # @return [String] file path
53
+ #
54
+ def self.lookup(dir=nil)
55
+ dir = dir || Dir.pwd
56
+ home = File.expand_path('~')
57
+ while dir != '/' && dir != home
58
+ if file = Dir.glob(File.join(dir, PATTERN), File::FNM_CASEFOLD).first
59
+ return new(File.dirname(file))
60
+ end
61
+ dir = File.dirname(dir)
62
+ end
63
+ return nil
64
+ end
65
+
66
+ #
67
+ # Initialize new ProjectConfig.
68
+ #
69
+ # @param [String] root
70
+ # Project root directory.
71
+ #
72
+ def initialize(root)
73
+ @root = root
74
+ end
75
+
76
+ #
77
+ # Project root directory.
78
+ #
79
+ # @return [String] project's root directory
80
+ #
81
+ attr :root
82
+
83
+ #
84
+ # Alias for #root.
85
+ #
86
+ alias :directory :root
87
+
88
+ #
89
+ # Configuration store tracks a project's confirguration entries.
90
+ #
91
+ def store
92
+ @store ||= Store.new(*source)
93
+ end
94
+
95
+ #
96
+ # The file path of the project's configuration file.
97
+ #
98
+ # @return [String] path to configuration file
99
+ #
100
+ def source
101
+ Dir.glob(File.join(root, PATTERN), File::FNM_CASEFOLD)
102
+ end
103
+
104
+ #
105
+ # List of configuration profiles.
106
+ #
107
+ # @return [Array] profile names
108
+ #
109
+ def profiles(tool)
110
+ store.profiles(tool)
111
+ end
112
+
113
+ #
114
+ # Project properties.
115
+ #
116
+ # @todo Use cascading class, e.g. Confstruct.
117
+ #
118
+ def properties
119
+ dotruby = File.join(directory,'.ruby')
120
+ if File.exist?(dotruby)
121
+ data = YAML.load_file(dotruby)
122
+ OpenStruct.new(data)
123
+ else
124
+ OpenStruct.new
125
+ end
126
+ end
127
+
128
+ #
129
+ # Create a configuration controller.
130
+ #
131
+ # @param [Object] scope
132
+ # Context for which controller is being created.
133
+ #
134
+ # @param [Symbol] tool
135
+ # The tool of the configuration to select.
136
+ #
137
+ def controller(scope, tool, options={})
138
+ profile = options[:profile]
139
+ configs = store.lookup(tool, profile)
140
+ Controller.new(scope, *configs)
141
+ end
142
+
143
+ #
144
+ # Iterate over each configurations.
145
+ #
146
+ def each(&block)
147
+ store.each(&block)
148
+ end
149
+
150
+ #
151
+ # The number of configurations.
152
+ #
153
+ # @return [Fixnum] config count
154
+ #
155
+ def size
156
+ store.size
157
+ end
158
+
159
+ end
160
+
161
+ end
@@ -0,0 +1,182 @@
1
+ module Confection
2
+
3
+ class Store
4
+
5
+ include Enumerable
6
+
7
+ =begin
8
+ #
9
+ # Bootstrap the system, loading current configurations.
10
+ #
11
+ def bootstrap
12
+ if file
13
+ @config[root] = []
14
+ begin
15
+ DSL.load_file(file)
16
+ rescue => e
17
+ raise e if $DEBUG
18
+ warn e.message
19
+ end
20
+ end
21
+ @config[root]
22
+ end
23
+ =end
24
+
25
+ #
26
+ def initialize(*sources)
27
+ @sources = sources
28
+
29
+ @list = []
30
+
31
+ sources.each do |source|
32
+ if File.file?(source)
33
+ parse(source)
34
+ else
35
+ # ignore directories
36
+ end
37
+ end
38
+ end
39
+
40
+ #
41
+ attr :sources
42
+
43
+ #
44
+ def parse(file)
45
+ DSL.parse(self, file)
46
+ end
47
+
48
+ #
49
+ # Iterate over each configurations.
50
+ #
51
+ def each(&block)
52
+ @list.each(&block)
53
+ end
54
+
55
+ #
56
+ # The number of configurations.
57
+ #
58
+ # @return [Fixnum] config count
59
+ #
60
+ def size
61
+ @list.size
62
+ end
63
+
64
+ #
65
+ # Add as configuratio to the store.
66
+ #
67
+ def <<(conf)
68
+ raise TypeError, "not a configuration instance -- `#{conf}'" unless Config === conf
69
+ @list << conf
70
+ end
71
+
72
+ #
73
+ # Add a list of configs.
74
+ #
75
+ def concat(configs)
76
+ configs.each{ |c| self << c }
77
+ end
78
+
79
+ #
80
+ # Lookup configuration by tool and profile name.
81
+ #
82
+ # @todo Future versions should allow this to handle regex and fnmatches.
83
+ #
84
+ def lookup(tool, profile=nil)
85
+ if profile == '*'
86
+ select do |c|
87
+ c.tool.to_sym == tool.to_sym
88
+ end
89
+ else
90
+ profile = profile.to_sym if profile
91
+
92
+ select do |c|
93
+ c.tool.to_sym == tool.to_sym && c.profile == profile
94
+ end
95
+ end
96
+ end
97
+
98
+ #
99
+ # Returns list of profiles collected from all configs.
100
+ #
101
+ def profiles(tool)
102
+ names = []
103
+ each do |c|
104
+ names << c.profile if c.tool == tool.to_sym
105
+ end
106
+ names.uniq
107
+ end
108
+
109
+ #
110
+ # Clear configs.
111
+ #
112
+ def clear!
113
+ @list = []
114
+ end
115
+
116
+ #
117
+ def first
118
+ @list.first
119
+ end
120
+
121
+ #
122
+ def last
123
+ @list.last
124
+ end
125
+
126
+ #
127
+ #def config(*args, &block)
128
+ # dsl.config(*args, &block)
129
+ #end
130
+
131
+ #
132
+ #def controller(scope, name, profile=nil)
133
+ # configs = lookup(name, profile)
134
+ # Controller.new(scope, *configs)
135
+ #end
136
+
137
+ #
138
+ # Import configuration from another project.
139
+ #
140
+ def import(tool, profile, options, &block)
141
+ from_tool = options[:tool] || tool
142
+ from_profile = options[:profile] || profile
143
+
144
+ case from = options[:from]
145
+ when String, Symbol
146
+ project = Project.load(from.to_s)
147
+ store = project ? project.store : nil
148
+ else
149
+ from = '(self)'
150
+ store = self
151
+ end
152
+
153
+ raise "no configuration found in `#{from}'" unless store
154
+
155
+ configs = store.lookup(from_tool, from_profile)
156
+
157
+ configs.each do |config|
158
+ new_config = config.copy(:tool=>tool, :profile=>profile)
159
+
160
+ #new_options = @_options.dup
161
+ #new_options[:tool] = tool
162
+ #new_options[:profile] = profile
163
+ #new_options[:block] = config.block
164
+ #new_options[:text] = config.text
165
+
166
+ # not so sure about this one
167
+ if String === new_config.value
168
+ new_config.value += ("\n" + options[:text].to_s) if options[:text]
169
+ end
170
+
171
+ self << new_config
172
+ end
173
+
174
+ #if block
175
+ # self << Config::Block.new(tool, profile, nil, &block)
176
+ #end
177
+ end
178
+
179
+ end
180
+
181
+ end
182
+
@@ -0,0 +1,33 @@
1
+ = Confection
2
+
3
+ The idea of confection is a unified configuration management across multiple
4
+ tools for Ruby. The structure of a confection configuration file is very simple.
5
+ It is a ruby script sectioned into named blocks:
6
+
7
+ config :rake do
8
+ # ... rake tasks ...
9
+ end
10
+
11
+ config :vclog do
12
+ # ... configure vclog ...
13
+ end
14
+
15
+ Utilization of the these configurations is strictly up to the consuming
16
+ application. For example, save native support in Rake itself, we can add
17
+ to a Rakefile:
18
+
19
+ require 'confection'
20
+
21
+ confection('rake').call
22
+
23
+ ANALYSIS:
24
+
25
+ config :qed, :coverage, -> do
26
+ name 'Tommy'
27
+ age 42
28
+ end
29
+
30
+ config :qed, :coverage do
31
+ puts "Scripted"
32
+ end
33
+
data/spec/01_dsl.md ADDED
@@ -0,0 +1,69 @@
1
+ # DSL
2
+
3
+ The DSL class handle evaluation of a project configuration file.
4
+
5
+ store = Confection::Store.new
6
+
7
+ dsl = Confection::DSL.new(store)
8
+
9
+ The DSL instance will have a cached binding.
10
+
11
+ #dsl.__binding__ == dsl.__binding__
12
+
13
+ We can use the `#instance_eval` method to evaluate a configuration for our
14
+ demonstration.
15
+
16
+ dsl.instance_eval(<<-HERE)
17
+ config :sample1 do
18
+ "block code"
19
+ end
20
+ HERE
21
+
22
+ Evaluation of a configuration file, populate the Confection.config instance.
23
+
24
+ sample = store.last
25
+ sample.tool #=> :sample1
26
+ sample.profile #=> nil
27
+ sample.class #=> Confection::Config
28
+
29
+ A profile can be used as a means fo defining multiple configuration options
30
+ for a single tool. This can be done by setting the second argument to a Symbol.
31
+
32
+ dsl.instance_eval(<<-HERE)
33
+ config :sample2, :opt1 do
34
+ "block code"
35
+ end
36
+ HERE
37
+
38
+ sample = store.last
39
+ sample.tool #=> :sample2
40
+ sample.profile #=> :opt1
41
+
42
+ Or it can be done by using a `profile` block.
43
+
44
+ dsl.instance_eval(<<-HERE)
45
+ profile :opt1 do
46
+ config :sample2 do
47
+ "block code"
48
+ end
49
+ end
50
+ HERE
51
+
52
+ sample = store.last
53
+ sample.tool #=> :sample2
54
+ sample.profile #=> :opt1
55
+
56
+ Different types of configuration can be defined. For instance, if a multi-line
57
+ string is passed to the `config` method will be a text-based configuration.
58
+
59
+ dsl.instance_eval(<<-HERE)
60
+ config :sample3, %{
61
+ text config
62
+ }
63
+ HERE
64
+
65
+ sample = store.last
66
+ sample.tool #=> :sample3
67
+ sample.profile #=> nil
68
+ sample.to_s.strip.assert == "text config"
69
+
data/spec/02_import.md ADDED
@@ -0,0 +1,52 @@
1
+ # Importing
2
+
3
+ ## Configuration Importing
4
+
5
+ Configurations can be imported from another project
6
+ using the `:from` option.
7
+
8
+ store = Confection::Store.new
9
+
10
+ dsl = Confection::DSL.new(store)
11
+
12
+ dsl.config :qed, :profile=>'example', :from=>'qed'
13
+
14
+ store.size.assert == 1
15
+
16
+ The configuration can also be imported from a different profile.
17
+
18
+ dsl.config :qed, :coverage, :from=>'qed', :profile=>:simplecov
19
+
20
+ store.size.assert == 2
21
+
22
+ Although it will rarely be useful, it may also be imported from another tool.
23
+
24
+ dsl.config :example, :from=>'qed', :tool=>:sample
25
+
26
+ Imported configurations can also be augmented via a block.
27
+
28
+ store = Confection::Store.new
29
+
30
+ dsl = Confection::DSL.new(store)
31
+
32
+ dsl.config :qed, :from=>'qed', :profile=>:simplecov do
33
+ # additional code here
34
+ end
35
+
36
+ store.size.assert == 2
37
+
38
+ Technically this last form just creates two configurations for the same
39
+ tool and profile, but the ultimate effect is the same.
40
+
41
+ ## Script Importing
42
+
43
+ Library files can be imported directly into configuration blocks via the
44
+ `#import` method.
45
+
46
+ dsl.config :example do
47
+ import "fruitbasket/example.rb"
48
+ end
49
+
50
+ This looks up the file via the `finder` gem and then evals it in the context
51
+ of the config block.
52
+
data/spec/03_store.md ADDED
@@ -0,0 +1,20 @@
1
+ ## Store
2
+
3
+ A Confection::Store encapsulates the list of configurations that belong
4
+ to a project.
5
+
6
+ store = Confection::Store.new
7
+
8
+ Only Config instance can be added to a store. Any other type of object
9
+ will raise an error.
10
+
11
+ expect TypeError do
12
+ store << 1
13
+ end
14
+
15
+ We can get a list of profiles for a given tool.
16
+
17
+ profiles = store.profiles(:text)
18
+
19
+ profiles.assert == []
20
+
@@ -0,0 +1,68 @@
1
+ # Controller
2
+
3
+ When working with configurations, Confection wraps configurations in a
4
+ Controller instance.
5
+
6
+ An empty controller can be made simply enough.
7
+
8
+ Confection::Controller.new(self, *[])
9
+
10
+ The #confection method simple calls this with the configs it finds.
11
+
12
+ ctrl = config(:block)
13
+
14
+ Confection::Controller.assert === ctrl
15
+
16
+ A controller will most oftern encapsulate just a sigle configuration,
17
+ but it may contain more if the search parameters used to create it
18
+ returned more than one matching configuration. We can see how many
19
+ configurations the controller is harnessing using the `#size` method.
20
+
21
+ ctrl.size.assert == 1
22
+
23
+ With the controller, we can utilize the configuration(s) it encapsulates
24
+ through the handful of methods it provides for doing so. Probably the
25
+ most useful, which applies to Ruby-based configurations is the `#call`
26
+ methods. This will execute the configuration script in the context
27
+ in which it was defined.
28
+
29
+ result = ctrl.call
30
+
31
+ result.assert == "example block config"
32
+
33
+ Instead of being executed in the context in which a configuration was
34
+ defined, it can be executed in the current scope using the #exec method.
35
+
36
+ result = ctrl.exec
37
+
38
+ result.assert == "example block config"
39
+
40
+ Of course, as this example only outputs a string, we won't notice any
41
+ difference here.
42
+
43
+ Lastly, script based configurations can be executed in the TOPLEVEL
44
+ context by using `#main_exec`, or its alias `#load`.
45
+
46
+ result = ctrl.main_exec
47
+
48
+ result.assert == "example block config"
49
+
50
+ The controller can be converted to a Proc object, in which case the
51
+ underlying execution is equivalent to using `#exec`. This allows
52
+ the procedure to be evaluated in other bindings as needed.
53
+
54
+ proc = ctrl.to_proc
55
+
56
+ result = proc.call
57
+
58
+ result.assert == "example block config"
59
+
60
+ For text configuration, the controller will concat each configuration's
61
+ content.
62
+
63
+ ctrl = config(:text)
64
+
65
+ text = ctrl.to_s
66
+
67
+ text.strip.assert == 'example text config'
68
+
data/spec/05_config.md ADDED
@@ -0,0 +1,99 @@
1
+ # Config Classes
2
+
3
+ There are three classes of configuration: test, data and block. Block
4
+ configurations encapsulate a block of Ruby code. Text configurations
5
+ simply contain a text string --whatever that string may represent.
6
+ Data configuration contantain a table of key-value pairs.
7
+
8
+ ## Block Configuration
9
+
10
+ File configuration come from separate files rather then from definitions
11
+ in a project's master configuration file.
12
+
13
+ config = confection(:block).first
14
+
15
+ Confection::Config.assert === config
16
+
17
+ A Ruby-based configuration file, like our example, can be called via the `#call`
18
+ method. This evaluates the code at the TOPLEVEL, like standard `Kernel.load`
19
+ would.
20
+
21
+ result = config.call
22
+
23
+ result.assert == "example block config"
24
+
25
+ The call can also be converted into a Proc object via `#to_proc`. This uses
26
+ `instance_eval` internally, so that the Proc object can be evaluated in
27
+ any context it may be needed.
28
+
29
+ proc = config.to_proc
30
+
31
+ Proc.assert === proc
32
+
33
+ result = proc.call
34
+
35
+ result.strip.assert == "example block config"
36
+
37
+
38
+ ## Text Configuraiton
39
+
40
+ Text-based configurations
41
+
42
+ config = confection(:text).first
43
+
44
+ Confection::Config.assert === config
45
+
46
+ result = config.to_s
47
+
48
+ result.strip.assert == "example text config"
49
+
50
+ For a text-based configuration `#call` does the same thing as `#to_s`.
51
+
52
+ result = config.call
53
+
54
+ result.strip.assert == "example text config"
55
+
56
+ As with the other configuration classes, we may also convert this call
57
+ into a Proc instance.
58
+
59
+ proc = config.to_proc
60
+
61
+ Proc.assert === proc
62
+
63
+ The configuration object can be copied, with a special `#copy` method
64
+ that accepts option parameters for changing the tool or profile of the copy.
65
+
66
+ alt = config.copy(:profile=>:alt)
67
+
68
+ alt.profile.assert == :alt
69
+
70
+
71
+ ## Data Configuration
72
+
73
+ Data-based configuration.
74
+
75
+ config = confection(:example, :data).first
76
+
77
+ Confection::Config.assert === config
78
+
79
+ result = config.to_h
80
+
81
+ result.assert == {:name=>'Tommy', :age=>42 }
82
+
83
+ For a Data-based configuration `#call` does the same thing as `#to_data`.
84
+
85
+ data = OpenStruct.new
86
+
87
+ result = config.call(data)
88
+
89
+ data.to_h.assert == {:name=>'Tommy', :age=>42 }
90
+
91
+ As with the other configuration classes, we may also convert this call
92
+ into a Proc instance.
93
+
94
+ proc = config.to_proc
95
+
96
+ Proc.assert === proc
97
+
98
+ This just encapsulates the `#to_data` call in a lambda.
99
+
data/spec/06_manage.md ADDED
@@ -0,0 +1,38 @@
1
+ # Manage
2
+
3
+ The Confection module has some convenice class methods for working
4
+ with the configuration of the *current* project --the one relative
5
+ to the current working directory.
6
+
7
+ The current project root directory can be had via the `current_directory`
8
+ method.
9
+
10
+ Confection.current_directory
11
+
12
+ The Project instance can be had via the `current_project` method.
13
+
14
+ project = Confection.current_project
15
+
16
+ Confection::Project.assert === project
17
+
18
+ The configuration properties of the current project can be
19
+ had via the `properties` method.
20
+
21
+ Confection.properties
22
+
23
+ The profile names can be looked up for any given tool via the `profiles`
24
+ method.
25
+
26
+ Confection.profiles(:file)
27
+
28
+ The number of configurations in the current project can be had via
29
+ the `size` method. (This is the number of configurations we have
30
+ defined in our test fixture.)
31
+
32
+ Confection.size.assert == 3
33
+
34
+ And we can loop through each configuration via the `each` method.
35
+
36
+ Confection.each{ |c| c }
37
+
38
+
@@ -0,0 +1 @@
1
+ require 'ae'
@@ -0,0 +1,8 @@
1
+ require 'confection'
2
+
3
+ When 'configuration file `(((\S+)))` containing' do |slots, text|
4
+ Confection.clear!
5
+ fname = [slots].flatten.first # temporary transition to new QED
6
+ File.open(fname, 'w'){ |f| f << text }
7
+ end
8
+
@@ -0,0 +1,10 @@
1
+ # Setup the fixtures.
2
+
3
+ dir = File.dirname(__FILE__) + '/fixture'
4
+ Dir.entries(dir).each do |file|
5
+ next if file == '.' or file == '..'
6
+ path = File.join(dir, file)
7
+ next if File.directory?(path)
8
+ FileUtils.install(path, Dir.pwd)
9
+ end
10
+
@@ -0,0 +1,15 @@
1
+ # exmaple configuration file
2
+
3
+ config :block do
4
+ "example block config"
5
+ end
6
+
7
+ config :text do
8
+ "example text config"
9
+ end
10
+
11
+ config :example, :data do |ex|
12
+ ex.name = 'Tommy'
13
+ ex.age = 42
14
+ end
15
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: confection
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-03-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: finder
16
- requirement: &70312239870960 !ruby/object:Gem::Requirement
16
+ requirement: &69827679742240 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70312239870960
24
+ version_requirements: *69827679742240
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: facets
27
- requirement: &70312239886780 !ruby/object:Gem::Requirement
27
+ requirement: &69827679741700 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70312239886780
35
+ version_requirements: *69827679741700
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: blankslate
38
- requirement: &70312239886280 !ruby/object:Gem::Requirement
38
+ requirement: &69827679741200 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70312239886280
46
+ version_requirements: *69827679741200
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: detroit
49
- requirement: &70312239885780 !ruby/object:Gem::Requirement
49
+ requirement: &69827679740700 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70312239885780
57
+ version_requirements: *69827679740700
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: qed
60
- requirement: &70312239885280 !ruby/object:Gem::Requirement
60
+ requirement: &69827679740200 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70312239885280
68
+ version_requirements: *69827679740200
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: ae
71
- requirement: &70312239884780 !ruby/object:Gem::Requirement
71
+ requirement: &69827679739700 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70312239884780
79
+ version_requirements: *69827679739700
80
80
  description: Confection is a multi-tenant configuration system for Ruby projects.
81
81
  email:
82
82
  - transfire@gmail.com
@@ -92,11 +92,28 @@ files:
92
92
  - lib/confection/basic_object.rb
93
93
  - lib/confection/config.rb
94
94
  - lib/confection/controller.rb
95
+ - lib/confection/core_ext.rb
96
+ - lib/confection/current.rb
95
97
  - lib/confection/dsl.rb
98
+ - lib/confection/hash_builder.rb
99
+ - lib/confection/project.rb
100
+ - lib/confection/store.rb
96
101
  - lib/confection.rb
102
+ - spec/00_concept.md
103
+ - spec/01_dsl.md
104
+ - spec/02_import.md
105
+ - spec/03_store.md
106
+ - spec/04_controller.md
107
+ - spec/05_config.md
108
+ - spec/06_manage.md
109
+ - spec/applique/ae.rb
110
+ - spec/applique/file.rb
111
+ - spec/applique/fixture/confile.rb
112
+ - spec/applique/fixture.rb
97
113
  - LICENSE.txt
98
114
  - HISTORY.md
99
115
  - README.md
116
+ - Confile.rb
100
117
  homepage: http://rubyworks.github.com/confection
101
118
  licenses:
102
119
  - BSD-2-Clause