dotruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.index +55 -0
- data/.yardopts +10 -0
- data/HISTORY.md +10 -0
- data/LICENSE.txt +23 -0
- data/README.md +283 -0
- data/lib/dotruby.rb +25 -0
- data/lib/dotruby/api.rb +106 -0
- data/lib/dotruby/constant.rb +55 -0
- data/lib/dotruby/dsl.rb +125 -0
- data/lib/dotruby/tweaks/rake.rb +33 -0
- data/lib/dotruby/tweaks/rspec.rb +1 -0
- data/lib/dotruby/tweaks/rubytest.rb +1 -0
- data/spec/helper.rb +1 -0
- data/spec/spec_api.rb +6 -0
- metadata +114 -0
data/.index
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
---
|
2
|
+
revision: 2013
|
3
|
+
type: ruby
|
4
|
+
sources:
|
5
|
+
- var
|
6
|
+
authors:
|
7
|
+
- name: trans
|
8
|
+
email: transfire@gmail.com
|
9
|
+
organizations:
|
10
|
+
- name: Rubyworks
|
11
|
+
requirements:
|
12
|
+
- groups:
|
13
|
+
- test
|
14
|
+
development: true
|
15
|
+
name: qed
|
16
|
+
- groups:
|
17
|
+
- test
|
18
|
+
development: true
|
19
|
+
name: ae
|
20
|
+
- groups:
|
21
|
+
- build
|
22
|
+
development: true
|
23
|
+
name: detroit
|
24
|
+
conflicts: []
|
25
|
+
alternatives: []
|
26
|
+
resources:
|
27
|
+
- type: home
|
28
|
+
uri: http://rubyworks.github.com/dotruby
|
29
|
+
label: Homepage
|
30
|
+
- type: code
|
31
|
+
uri: http://github.com/rubyworks/dotruby
|
32
|
+
label: Source Code
|
33
|
+
- type: mail
|
34
|
+
uri: http://groups.google.com/group/rubyworks-mailinglist
|
35
|
+
label: Mailing List
|
36
|
+
repositories:
|
37
|
+
- name: upstream
|
38
|
+
scm: git
|
39
|
+
uri: git@github.com:rubyworks/dotruby.git
|
40
|
+
categories: []
|
41
|
+
copyrights:
|
42
|
+
- holder: Rubyworks
|
43
|
+
year: '2013'
|
44
|
+
license: BSD-2-Clause
|
45
|
+
customs: []
|
46
|
+
paths:
|
47
|
+
lib:
|
48
|
+
- lib
|
49
|
+
created: '2013-01-19'
|
50
|
+
summary: Transparent Runtime Configuration for Ruby
|
51
|
+
title: DotRuby
|
52
|
+
version: 0.1.0
|
53
|
+
name: dotruby
|
54
|
+
description: DotRuby is a universal runtime configuration system for Ruby tools.
|
55
|
+
date: '2013-01-22'
|
data/.yardopts
ADDED
data/HISTORY.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
BSD-2-Clause License
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice,
|
7
|
+
this list of conditions and the following disclaimer.
|
8
|
+
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
11
|
+
documentation and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
14
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
16
|
+
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
17
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
18
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
19
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
20
|
+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
21
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
22
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
data/README.md
ADDED
@@ -0,0 +1,283 @@
|
|
1
|
+
# DotRuby (formerly known as Ruby Courtier)
|
2
|
+
|
3
|
+
**Universal Runtime Configuration for Ruby Tools**
|
4
|
+
|
5
|
+
[Homepage](http://rubyworks.github.com/dotruby) /
|
6
|
+
[Report Issue](http://github.com/rubyworks/dotruby/issues) /
|
7
|
+
[Source Code](http://github.com/rubyworks/dotruby)
|
8
|
+
( [![Build Status](https://secure.travis-ci.org/rubyworks/dotruby.png)](http://travis-ci.org/rubyworks/dotruby) )
|
9
|
+
|
10
|
+
|
11
|
+
## About
|
12
|
+
|
13
|
+
DotRuby is a is multi-tenant runtime configuration system for Ruby tools.
|
14
|
+
It is designed to facilitate Ruby-based configuration for multiple
|
15
|
+
tools in a single file, and designed to work whether the tool has
|
16
|
+
built-in support for DotRuby or not. The syntax is simple, universally
|
17
|
+
applicable, and... oh yeah, damn clever.
|
18
|
+
|
19
|
+
DotRuby can be used with any Ruby-based commandline tool or library utilized by
|
20
|
+
such tool, where there exists some means of configuring it via a toplevel or global
|
21
|
+
interface; or the tool has been designed to directly support DotRuby, of course.
|
22
|
+
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
To use DotRuby with any tool, including those that do not in themselves have a
|
27
|
+
built-in dependency on DotRuby, first install the DotRuby library, typically
|
28
|
+
via RubyGems:
|
29
|
+
|
30
|
+
gem install dotruby
|
31
|
+
|
32
|
+
Then add `-rdotruby` to your system's `RUBYOPT` environment variable.
|
33
|
+
|
34
|
+
$ export RUBYOPT='-rdotruby'
|
35
|
+
|
36
|
+
You will want to add that to your `.bashrc`, `.profile` or equivalent configuration
|
37
|
+
script, so it is always available.
|
38
|
+
|
39
|
+
To use DotRuby with tools that support DotRuby directly, there is likely nothing
|
40
|
+
to install. Installing the tool should install `dotruby` via a dependency and
|
41
|
+
load runtime configurations when the tool is used.
|
42
|
+
|
43
|
+
|
44
|
+
## Instruction
|
45
|
+
|
46
|
+
### Configuring
|
47
|
+
|
48
|
+
To use DotRuby in a project create a configuration file called `.ruby`.
|
49
|
+
(Hey, now you know why it has the name, *DotRuby*!). In this file add
|
50
|
+
configuration code as you would normally do for a given library. The
|
51
|
+
only caveat is that all such configurations must be against a constant.
|
52
|
+
|
53
|
+
For example, let's say we need to configure RSpec. In the `.ruby` file we can
|
54
|
+
add the following.
|
55
|
+
|
56
|
+
RSpec.configure do |config|
|
57
|
+
config.color_enabled = true
|
58
|
+
config.tty = true
|
59
|
+
config.formatter = :documentation
|
60
|
+
end
|
61
|
+
|
62
|
+
This might seems pretty ordinary, but consider that the RSpec library hasn't
|
63
|
+
necessarily been loaded when this is evaluated! Think about that a bit
|
64
|
+
and we'll explain how it works below.
|
65
|
+
|
66
|
+
For another example, let's demonstrate how we could use this to configure Rake
|
67
|
+
tasks. Rake is not the most obvious choice, since developers are just as happy
|
68
|
+
to keep using a Rakefile. That's fine. But using Rake as an example serves to
|
69
|
+
show that it *can* be done, and also it makes a good tie-in with next example.
|
70
|
+
|
71
|
+
Rake.file do
|
72
|
+
desc 'generate yard docs'
|
73
|
+
task :yard do
|
74
|
+
sh 'yard'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Now when `rake` is run the tasks defined in this configuration will be available.
|
79
|
+
|
80
|
+
Getting back to our Rake example, you might wonder why anyone would want to do
|
81
|
+
this. That's where the *multi-tenancy* comes into play. Let's add another
|
82
|
+
configuration.
|
83
|
+
|
84
|
+
title = "MyApp"
|
85
|
+
|
86
|
+
Rake.file do
|
87
|
+
desc 'generate yard docs'
|
88
|
+
task :yard do
|
89
|
+
sh "yard doc --title #{title}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
QED.config do |c|
|
94
|
+
c.title = "#{title} Demos"
|
95
|
+
end
|
96
|
+
|
97
|
+
Now we have configuration for both the `rake` tool and the `qed` tool in
|
98
|
+
a single file. Thus we gain the advantage of reducing the file count of our
|
99
|
+
project while pulling our tool configurations together into one place.
|
100
|
+
Moreover, these configurations can potentially share settings as demonstrated
|
101
|
+
here via the `title` local variable.
|
102
|
+
|
103
|
+
### Tagging
|
104
|
+
|
105
|
+
Some commands don't correspond to their API namespaces. For example, in the
|
106
|
+
above example we configured QED's title option. But that is actually of
|
107
|
+
use when running the `qedoc` command, which belongs to the same library.
|
108
|
+
We can easily tell DotRuby to expect this by adding a `tag`.
|
109
|
+
|
110
|
+
tag :QED, :command=>'qedoc'
|
111
|
+
|
112
|
+
DotRuby's configurations are triggered by three criteria: a constant,
|
113
|
+
a command and a feature. In the above tag example, the constant is
|
114
|
+
`QED`, the command is `qedoc` and the feature is not given so it defaults
|
115
|
+
to the constant name downcased, i.e. `qed`. If need be we can specify a
|
116
|
+
different feature via the `:feature` option.
|
117
|
+
|
118
|
+
### Profiles
|
119
|
+
|
120
|
+
Sometimes you need to configure a tool with different settings for different
|
121
|
+
circumstances. If the tool doesn't have built in support for this, DotRuby
|
122
|
+
provides some convenience methods for handling this via environment variables.
|
123
|
+
|
124
|
+
A `profile` block can be used to only run if `ENV['profile']', or as a nice
|
125
|
+
shortcut `ENV['p']` is set to the given name.
|
126
|
+
|
127
|
+
profile :doc do
|
128
|
+
RSpec.configure do |config|
|
129
|
+
config.color_enabled = true
|
130
|
+
config.tty = true
|
131
|
+
config.formatter = :documentation
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
To be clear why this is just a convenience method, it is essentially the same
|
136
|
+
as doing:
|
137
|
+
|
138
|
+
if 'doc' === (ENV['profile'] || ENV['p'])
|
139
|
+
...
|
140
|
+
end
|
141
|
+
|
142
|
+
When utilizing the tool, set the `profile` via an environment variable.
|
143
|
+
|
144
|
+
$ profile=cov qed
|
145
|
+
|
146
|
+
Or for additional convenience just `p`:
|
147
|
+
|
148
|
+
$ p=cov qed
|
149
|
+
|
150
|
+
### Environments
|
151
|
+
|
152
|
+
DotRuby also provided the `environment` convenience method, which is along
|
153
|
+
the same line but allows any environment variable to be used.
|
154
|
+
|
155
|
+
environment :testing => 'yes' do
|
156
|
+
...
|
157
|
+
end
|
158
|
+
|
159
|
+
Again, this is just a shortcut for:
|
160
|
+
|
161
|
+
if 'yes' === ENV['testing']
|
162
|
+
...
|
163
|
+
end
|
164
|
+
|
165
|
+
It is recommended that you use the `profile` instead of `environment` unless their
|
166
|
+
is specific reason not to do so. This makes it easier for other to utilize, instead
|
167
|
+
of having to recollect which environment variables where used for what configurations.
|
168
|
+
|
169
|
+
### Tweaks
|
170
|
+
|
171
|
+
In the Rake example, you might notice that `Rake.file` isn't an official method
|
172
|
+
of the Rake API. This is called a *tweak* and is built-in with DotRuby. Some
|
173
|
+
tools that we might wish to use with DotRuby don't have an interface that
|
174
|
+
suffices, in these cases a tweak can be used to give it one.
|
175
|
+
|
176
|
+
If there is a tool you would like to configure with DotRuby, but it doesn't
|
177
|
+
provided a means for it, and a reasonably simple tweak can make it viable,
|
178
|
+
please submit a patch and it will be added to DotRuby. And let the tool creator
|
179
|
+
know about it! Hopefully, in time tool developers will make the tweak unnecessary.
|
180
|
+
|
181
|
+
### Importing
|
182
|
+
|
183
|
+
**(Comming soon)**
|
184
|
+
|
185
|
+
Configurations can also be pulled in from other gems using the `import` command.
|
186
|
+
For instance, if we wanted to reuse the Rake configurations as defined in
|
187
|
+
the `QED` gem:
|
188
|
+
|
189
|
+
import :Rake, :from=>'qed'
|
190
|
+
|
191
|
+
If a particular profile or environment is needed, these can specified as options.
|
192
|
+
|
193
|
+
import :RSpec, :from=>'rspec', :profile=>'simplecov'
|
194
|
+
|
195
|
+
As long as a project includes its `.ruby` file (and any local imported files)
|
196
|
+
in it's gem package, it's possible to share configurations in this manner.
|
197
|
+
|
198
|
+
Generally we want all our configurations stored in a single file, but if need be
|
199
|
+
the `import` method can be used to place configuration in multiple files.
|
200
|
+
Simple use a local path `import` method to load them, e.g.
|
201
|
+
|
202
|
+
import './config/*.dotrb'
|
203
|
+
|
204
|
+
DotRuby translates the initial dot into a path relative to the file itself,
|
205
|
+
i.e. `__dir__`. Why can't we leave off the initial dot? If we did import
|
206
|
+
would work like require and try to load the file from a gem --however,
|
207
|
+
there is an issue with implementing this that needs to be resolved with
|
208
|
+
Ruby itself (autoload), so this feature is on hold for the time being.
|
209
|
+
|
210
|
+
### Third Party Support
|
211
|
+
|
212
|
+
To support DotRuby, all developers have to do is make sure their tools
|
213
|
+
have a way of being configured via a toplevel namespace constant.
|
214
|
+
|
215
|
+
It is also helps when the the library name to be required is the the same
|
216
|
+
as the library's namespace downcased. When it's not the same a `tag` entry
|
217
|
+
is needed to tell DotRuby from which feature to expect the constant. For
|
218
|
+
popular tools that have such a discrepancy, DotRuby provides *tweaks* that
|
219
|
+
take care of it automatically. But it's always best to follow the general
|
220
|
+
good practice that the gem name is the same as the lib name which is the same
|
221
|
+
as the namespace downcased.
|
222
|
+
|
223
|
+
Finally a third party tool can take the final step of full support by using
|
224
|
+
DotRuby as it preferred means of configuration. In that case, just make
|
225
|
+
sure to `require 'dotruby'`.
|
226
|
+
|
227
|
+
|
228
|
+
## How It Works
|
229
|
+
|
230
|
+
The design of DotRuby is actually quite clever. What it does is proxy all
|
231
|
+
calls to *virtual constants*, keeping a record of the messages sent to them.
|
232
|
+
When it is time to apply these configurations, it fins the ones that apply
|
233
|
+
to the given command and sends the recorded messages on the the real constants.
|
234
|
+
If those constants haven't been loaded yet, it adds a hook to `require` and
|
235
|
+
waits for the matching feature to load, at which time it applies the configuration.
|
236
|
+
In the way, DotRuby can actually be required before or after the library that
|
237
|
+
it will configure and it works regardless.
|
238
|
+
|
239
|
+
There is an unfortunate caveat here though. Luckily it will rarely be a real issue,
|
240
|
+
but it is possible for `autoload` to fowl up the works, b/c it does not call out
|
241
|
+
the standard require method. So there is no way override it and insert the necessary
|
242
|
+
hook. Again, this is not likely to be a problem, especially if good naming practices
|
243
|
+
are used, but it a good thing to know just in case you run into some unexpected
|
244
|
+
behavior.
|
245
|
+
|
246
|
+
|
247
|
+
## Dependencies
|
248
|
+
|
249
|
+
### Libraries
|
250
|
+
|
251
|
+
DotRuby depends on the [Finder](http://rubyworks.github.com/finder) library
|
252
|
+
to provide reliable load path and Gem searching. This is used when importing
|
253
|
+
configurations from other projects. (It's very much a shame Ruby and RubyGems
|
254
|
+
does not have this kind of functionality built-in.)
|
255
|
+
|
256
|
+
### Core Extensions
|
257
|
+
|
258
|
+
DotRuby uses two core extensions, `#to_h`, which applies to a few different
|
259
|
+
classes, and `String#tabto`. These are *copied* from
|
260
|
+
[Ruby Facets](http://rubyworks.github.com/facets) to ensure a high
|
261
|
+
standard of interoperability.
|
262
|
+
|
263
|
+
Both of these methods have been suggested for inclusion in Ruby proper.
|
264
|
+
Please head over to Ruby Issue Tracker and add your support.
|
265
|
+
|
266
|
+
* http://bugs.ruby-lang.org/issues/749
|
267
|
+
* http://bugs.ruby-lang.org/issues/6056
|
268
|
+
|
269
|
+
|
270
|
+
## Release Notes
|
271
|
+
|
272
|
+
Please see HISTORY.md file.
|
273
|
+
|
274
|
+
|
275
|
+
## Copyrights & Licensing
|
276
|
+
|
277
|
+
DotRuby is copyrighted open-source software.
|
278
|
+
|
279
|
+
Copyright (c) 2011 Rubyworks. All rights reserved.
|
280
|
+
|
281
|
+
It is modifiable and redistributable in accordance with the **BSD-2-Clause** license.
|
282
|
+
|
283
|
+
See LICENSE.txt file for details.
|
data/lib/dotruby.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# DotRuby - Universal Runtime Configuration for Ruby Tools
|
2
|
+
#
|
3
|
+
# Q. What if a program needs to be configured, but it does not provide
|
4
|
+
# an interface via a constant? For example, what if it uses a global
|
5
|
+
# variable?
|
6
|
+
#
|
7
|
+
# A. Most likely the program has a toplevel namespace module. You
|
8
|
+
# can always call module_eval to handle it if there is no other means.
|
9
|
+
# You ccould alos define a *make-shift* extension method on it that does
|
10
|
+
# the dirty deed. If there is no such module, just make a *make-shift*
|
11
|
+
# module for it too.
|
12
|
+
#
|
13
|
+
# module ProgramWithoutNamespace
|
14
|
+
# def self.configure(settings)
|
15
|
+
# $dirty_program_settings = settings
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# We call this *tweaking*.
|
20
|
+
|
21
|
+
require 'dotruby/api'
|
22
|
+
|
23
|
+
DotRuby.configure!
|
24
|
+
|
25
|
+
# DotRuby Copyright (c) 2012 Rubyworks. All rights reserved. (BSD-2-Clause License)
|
data/lib/dotruby/api.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
module DotRuby
|
2
|
+
require 'dotruby/dsl'
|
3
|
+
require 'dotruby/constant'
|
4
|
+
|
5
|
+
#
|
6
|
+
def self.configuration
|
7
|
+
@configuration ||= DSL.new(dotruby_file)
|
8
|
+
end
|
9
|
+
|
10
|
+
# This is a convenience interfact to the configuration domain, which
|
11
|
+
# is useful for tweaks to redefine the default tag.
|
12
|
+
def self.default_tag(cname, command, feature=nil)
|
13
|
+
configuration.default_tag(cname, command, feature)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Configure the system.
|
17
|
+
#
|
18
|
+
# @return nothing
|
19
|
+
def self.configure!
|
20
|
+
return unless dotruby_file
|
21
|
+
|
22
|
+
dotruby = DotRuby.configuration
|
23
|
+
|
24
|
+
begin
|
25
|
+
require_relative "tweaks/#{DotRuby.command}"
|
26
|
+
rescue LoadError
|
27
|
+
end
|
28
|
+
|
29
|
+
# If the constant already exists, apply the configuration.
|
30
|
+
#
|
31
|
+
# Since Ruby provides no way to ask if a feature has been required or not,
|
32
|
+
# we can only condition application of pre-extisting constants on a
|
33
|
+
# matching command.
|
34
|
+
dotruby.tags.each do |cname, tags|
|
35
|
+
tags.each do |tag|
|
36
|
+
next unless Object.const_defined?(cname)
|
37
|
+
next unless DotRuby.command == tag.first # command of the tag
|
38
|
+
if config = dotruby.constants[name]
|
39
|
+
execute(&config)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# If the constant doesn't already exist, wait until it is required.
|
45
|
+
::Kernel.module_eval {
|
46
|
+
alias _require require
|
47
|
+
|
48
|
+
def require(fname)
|
49
|
+
_require(fname)
|
50
|
+
|
51
|
+
dotruby = DotRuby.configuration
|
52
|
+
command = DotRuby.command
|
53
|
+
dotruby.tags.each do |cname, tags|
|
54
|
+
tags.each do |tag|
|
55
|
+
next unless fname == tag.last # feature of the tag
|
56
|
+
next unless command == tag.first # command of the tag
|
57
|
+
if config = dotruby.constants[cname]
|
58
|
+
DotRuby.execute(&config)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module_function :require
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
# Current command.
|
69
|
+
#
|
70
|
+
# @return [String]
|
71
|
+
def self.command
|
72
|
+
ENV['command'] || File.basename($0)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Execute the configuration.
|
76
|
+
#
|
77
|
+
# @return nothing
|
78
|
+
def self.execute(&config)
|
79
|
+
config.call
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns the `.ruby` file of the current project.
|
83
|
+
#
|
84
|
+
# @return {String] The .ruby file of the project.
|
85
|
+
def self.dotruby_file
|
86
|
+
file = File.join(project_root, '.ruby')
|
87
|
+
return nil unless File.exist?(file)
|
88
|
+
return file
|
89
|
+
end
|
90
|
+
|
91
|
+
# Find the root directory of the current project.
|
92
|
+
#
|
93
|
+
# @return [String,nil] The root directory of the project.
|
94
|
+
def self.project_root(start_dir=Dir.pwd)
|
95
|
+
dir = start_dir
|
96
|
+
home = File.expand_path('~')
|
97
|
+
until dir == home || dir == '/'
|
98
|
+
if file = Dir[File.join(dir, '{.ruby,.git,.hg}')].first
|
99
|
+
return dir
|
100
|
+
end
|
101
|
+
dir = File.dirname(dir)
|
102
|
+
end
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module DotRuby
|
2
|
+
|
3
|
+
# The virtual constant class is a simple recorder. Every method
|
4
|
+
# called on it is recorded for later recall on the actual constant
|
5
|
+
# given by name.
|
6
|
+
#
|
7
|
+
# To invoke the recordeed calls on the real constant use `to_proc.call`.
|
8
|
+
#
|
9
|
+
class Constant < BasicObject
|
10
|
+
|
11
|
+
# Initialize configuration.
|
12
|
+
#
|
13
|
+
# @param [Symbol] Name of constant.
|
14
|
+
#
|
15
|
+
def initialize(name)
|
16
|
+
@name = name
|
17
|
+
@calls = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# An inspection string for the Configuration class.
|
21
|
+
#
|
22
|
+
# @return [String]
|
23
|
+
def inspect
|
24
|
+
"#<Constant #{@name}>"
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
def method_missing(s, *a, &b)
|
29
|
+
@calls << [s, a, b]
|
30
|
+
end
|
31
|
+
|
32
|
+
# TODO: Add support for const_missing? But these need
|
33
|
+
# to be recalled in order with method_missing.
|
34
|
+
|
35
|
+
#def const_missing(name)
|
36
|
+
# @calls << Configuration.new("#{@name}::#{name}")
|
37
|
+
#end
|
38
|
+
|
39
|
+
# Create a Proc instance that will recall the method
|
40
|
+
# invocations on the actual constant.
|
41
|
+
#
|
42
|
+
# @return [Proc]
|
43
|
+
def to_proc
|
44
|
+
name, calls = @name, @calls
|
45
|
+
::Proc.new do
|
46
|
+
const = ::Object.const_get(name)
|
47
|
+
calls.each do |s, a, b|
|
48
|
+
const.public_send(s, *a, &b)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/lib/dotruby/dsl.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
module DotRuby
|
2
|
+
|
3
|
+
# DotRuby DSL class is used to evaluate the `.ruby` configuration file.
|
4
|
+
#
|
5
|
+
class DSL < BasicObject #Module
|
6
|
+
include ::Kernel
|
7
|
+
|
8
|
+
# Initialize new DSL instance.
|
9
|
+
#
|
10
|
+
def initialize(file)
|
11
|
+
@file = file
|
12
|
+
|
13
|
+
@@default_tags ||= {}
|
14
|
+
@@defined_tags ||= {}
|
15
|
+
|
16
|
+
@@contants ||= {}
|
17
|
+
|
18
|
+
instance_eval(::File.read(file), file)
|
19
|
+
end
|
20
|
+
|
21
|
+
# The path of the current project's `.ruby` file.
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
attr :file
|
25
|
+
|
26
|
+
# Return recognizes tags.
|
27
|
+
#
|
28
|
+
# @return [Hash]
|
29
|
+
def tags
|
30
|
+
keys = @@default_tags.keys - @@defined_tags.keys
|
31
|
+
tags = @@defined_tags.dup
|
32
|
+
keys.each do |key|
|
33
|
+
tags[key] = [@@default_tags[key]]
|
34
|
+
end
|
35
|
+
tags
|
36
|
+
end
|
37
|
+
|
38
|
+
# Defined tags map constant names to a list of `[command, feature]` pairs.
|
39
|
+
#
|
40
|
+
# @return [Hash<Array>]
|
41
|
+
#def defined_tag
|
42
|
+
#end
|
43
|
+
|
44
|
+
# Table of constant configurations.
|
45
|
+
#
|
46
|
+
# @return [Hash]
|
47
|
+
def constants
|
48
|
+
@@contants
|
49
|
+
end
|
50
|
+
|
51
|
+
# Tag a constant to a command and/or feature.
|
52
|
+
#
|
53
|
+
def tag(constant, *target)
|
54
|
+
options = (::Hash === target.last ? target.pop : {})
|
55
|
+
target = target.first
|
56
|
+
|
57
|
+
command = options[:command] || target
|
58
|
+
feature = options[:feature] || target
|
59
|
+
|
60
|
+
tag = [command.to_s, feature.to_s]
|
61
|
+
|
62
|
+
@@defined_tags[constant] ||= []
|
63
|
+
@@defined_tags[constant] << tag unless @@defined_tags[constant].include?(tag)
|
64
|
+
@@defined_tags
|
65
|
+
end
|
66
|
+
|
67
|
+
# Set the default tag for a constant.
|
68
|
+
# Unlike defined tags, there can be only one associate for a default tag.
|
69
|
+
#
|
70
|
+
# @return [Hash<Array>]
|
71
|
+
def default_tag(cname, command, feature=nil)
|
72
|
+
@@default_tags[cname.to_sym] = [command.to_s, (feature || command).to_s]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Only configure if profile matches.
|
76
|
+
#
|
77
|
+
# @param [#===] match
|
78
|
+
# A String or Regexp or any other object that can
|
79
|
+
# check a match to a String via #===.
|
80
|
+
#
|
81
|
+
# @return nothing
|
82
|
+
def profile(match, &block)
|
83
|
+
if match === (ENV['profile'] || ENV['p'])
|
84
|
+
block.call
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Only configure if environment matches.
|
89
|
+
#
|
90
|
+
# @param [Hash<name,#===>] matches
|
91
|
+
# A Hash of String or Regexp or any other object that can
|
92
|
+
# check a match to a String via #===.
|
93
|
+
#
|
94
|
+
# @todo Should it be logical-or or logical-and?
|
95
|
+
#
|
96
|
+
# @return nothing
|
97
|
+
def environment(matches={}, &block)
|
98
|
+
if matches.any?{ |e, m| m === ENV[e] }
|
99
|
+
block.call
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Import configuration from an external source.
|
104
|
+
#
|
105
|
+
# @param [Symbol,String] Name of constant or file path.
|
106
|
+
#
|
107
|
+
# @return nothing
|
108
|
+
def import(name, options={})
|
109
|
+
raise 'import is not implemented yet'
|
110
|
+
end
|
111
|
+
|
112
|
+
# Constants provide configuration.
|
113
|
+
#
|
114
|
+
# @param [Symbol,String] cname
|
115
|
+
#
|
116
|
+
# @return [Constant]
|
117
|
+
def self.const_missing(cname)
|
118
|
+
@@default_tags[cname.to_sym] = [cname.to_s.downcase, cname.to_s.downcase]
|
119
|
+
|
120
|
+
@@contants[cname] ||= Constant.new(cname)
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
module Rake
|
4
|
+
|
5
|
+
# TODO: While probably a complete YAGNI, how might we load a .ruby rake config into a Rakefile?
|
6
|
+
|
7
|
+
# TODO: rake -T doesn't work, why?
|
8
|
+
|
9
|
+
# Use this method to add tasks to Rake.
|
10
|
+
def self.file(&config)
|
11
|
+
Module.new do
|
12
|
+
extend Rake::DSL
|
13
|
+
module_eval(&config)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Application
|
18
|
+
remove_const(:DEFAULT_RAKEFILES)
|
19
|
+
DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb', '.ruby']
|
20
|
+
#DEFAULT_RAKEFILES << '.ruby'
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.load_rakefile(path)
|
24
|
+
case File.basename(path)
|
25
|
+
when '.ruby'
|
26
|
+
# do nothing, DotRuby will do it
|
27
|
+
else
|
28
|
+
load(path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
DotRuby.default_tag(:RSpec, 'rspec', 'rspec/core')
|
@@ -0,0 +1 @@
|
|
1
|
+
DotRuby.default_tag(:Test, 'rubytest')
|
data/spec/helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'dotruby/api'
|
data/spec/spec_api.rb
ADDED
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dotruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- trans
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: qed
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: ae
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: detroit
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: DotRuby is a universal runtime configuration system for Ruby tools.
|
63
|
+
email:
|
64
|
+
- transfire@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files:
|
68
|
+
- LICENSE.txt
|
69
|
+
- HISTORY.md
|
70
|
+
- README.md
|
71
|
+
files:
|
72
|
+
- .index
|
73
|
+
- .yardopts
|
74
|
+
- lib/dotruby.rb
|
75
|
+
- lib/dotruby/api.rb
|
76
|
+
- lib/dotruby/tweaks/rubytest.rb
|
77
|
+
- lib/dotruby/tweaks/rake.rb
|
78
|
+
- lib/dotruby/tweaks/rspec.rb
|
79
|
+
- lib/dotruby/dsl.rb
|
80
|
+
- lib/dotruby/constant.rb
|
81
|
+
- spec/spec_api.rb
|
82
|
+
- spec/helper.rb
|
83
|
+
- LICENSE.txt
|
84
|
+
- HISTORY.md
|
85
|
+
- README.md
|
86
|
+
homepage: http://rubyworks.github.com/dotruby
|
87
|
+
licenses:
|
88
|
+
- BSD-2-Clause
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.8.24
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Transparent Runtime Configuration for Ruby
|
111
|
+
test_files:
|
112
|
+
- spec/spec_api.rb
|
113
|
+
- spec/helper.rb
|
114
|
+
has_rdoc:
|