dotruby 0.1.0
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/.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
|
+
( [](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:
|