raml 0.2.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/.ruby +42 -0
- data/.yardopts +8 -0
- data/COPYING.rdoc +31 -0
- data/HISTORY.rdoc +12 -0
- data/QED.rdoc +217 -0
- data/README.rdoc +92 -0
- data/lib/raml.rb +110 -0
- data/lib/raml.yml +42 -0
- data/lib/raml/core_ext.rb +13 -0
- data/lib/raml/eval_parser.rb +149 -0
- data/lib/raml/multi_value.rb +12 -0
- data/lib/raml/ripper_parser.rb +151 -0
- data/qed/applique/document.rb +4 -0
- data/qed/eval.rdoc +104 -0
- data/qed/read.rdoc +109 -0
- data/qed/samples/sample1.rml +7 -0
- data/qed/samples/sample2.rml +6 -0
- metadata +99 -0
data/.ruby
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
---
|
2
|
+
source:
|
3
|
+
- meta
|
4
|
+
authors:
|
5
|
+
- name: 7rans
|
6
|
+
email: transfire@gmail.com
|
7
|
+
copyrights:
|
8
|
+
- holder: Rubyworks
|
9
|
+
year: '2010'
|
10
|
+
replacements: []
|
11
|
+
alternatives: []
|
12
|
+
requirements:
|
13
|
+
- name: blankslate
|
14
|
+
- name: detroit
|
15
|
+
groups:
|
16
|
+
- build
|
17
|
+
development: true
|
18
|
+
- name: qed
|
19
|
+
groups:
|
20
|
+
- test
|
21
|
+
development: true
|
22
|
+
dependencies: []
|
23
|
+
conflicts: []
|
24
|
+
repositories: []
|
25
|
+
resources:
|
26
|
+
home: http://rubyworks.github.com/raml
|
27
|
+
code: http://github.com/rubyworks/raml
|
28
|
+
docs: http://rubydoc.info/gems/raml/frames
|
29
|
+
mail: http://groups.google.com/group/rubyworks-mailinglist
|
30
|
+
gems: http://rubygems.org/gems/raml
|
31
|
+
extra: {}
|
32
|
+
load_path:
|
33
|
+
- lib
|
34
|
+
revision: 0
|
35
|
+
created: '2010-09-21'
|
36
|
+
summary: Ruby Syntax Data Language
|
37
|
+
title: RAML
|
38
|
+
version: 0.2.0
|
39
|
+
name: raml
|
40
|
+
description: RAML is a Ruby-syntax-based data language.
|
41
|
+
organization: rubyworks
|
42
|
+
date: '2011-10-28'
|
data/.yardopts
ADDED
data/COPYING.rdoc
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
= COPYRIGHT NOTICES
|
2
|
+
|
3
|
+
== RAML
|
4
|
+
|
5
|
+
Copyright:: (c) 2010 Thomas Sawyer, Rubyworks
|
6
|
+
License:: BSD-2-Clause
|
7
|
+
Website:: http://rubyworks.github.com/raml
|
8
|
+
|
9
|
+
Copyright 2011 Thomas Sawyer. All rights reserved.
|
10
|
+
|
11
|
+
Redistribution and use in source and binary forms, with or without
|
12
|
+
modification, are permitted provided that the following conditions are met:
|
13
|
+
|
14
|
+
1. Redistributions of source code must retain the above copyright notice,
|
15
|
+
this list of conditions and the following disclaimer.
|
16
|
+
|
17
|
+
2. Redistributions in binary form must reproduce the above copyright
|
18
|
+
notice, this list of conditions and the following disclaimer in the
|
19
|
+
documentation and/or other materials provided with the distribution.
|
20
|
+
|
21
|
+
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
22
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
23
|
+
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
24
|
+
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
25
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
26
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
27
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
28
|
+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
29
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
30
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
|
data/HISTORY.rdoc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
= RELEASE HISTORY
|
2
|
+
|
3
|
+
== 0.1.0 | 2010-09-28
|
4
|
+
|
5
|
+
A very early release of RAML, presently only supporting an eval-based parser.
|
6
|
+
Ultimately the intent is to provide a true parser, that can restict the format
|
7
|
+
to pure data.
|
8
|
+
|
9
|
+
Changes:
|
10
|
+
|
11
|
+
* Initial implementation.
|
12
|
+
|
data/QED.rdoc
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
= RAML.eval
|
2
|
+
|
3
|
+
The RAML.eval() method parses a RAML document using the Kernel.eval.
|
4
|
+
In this way Ruby scripting can still be utilized within the document.
|
5
|
+
|
6
|
+
Require the RAML library.
|
7
|
+
|
8
|
+
require 'raml'
|
9
|
+
|
10
|
+
Given a RAML document:
|
11
|
+
|
12
|
+
website "http://rubygems.org"
|
13
|
+
|
14
|
+
We can load the text via the #load method. (Note above document text has
|
15
|
+
been placed in the @text variable.)
|
16
|
+
|
17
|
+
data = RAML.eval(@text)
|
18
|
+
|
19
|
+
data.assert == {:website=>"http://rubygems.org"}
|
20
|
+
|
21
|
+
One of the nicer features of RAML derives from Ruby's block notation, allowing
|
22
|
+
for nested entries.
|
23
|
+
|
24
|
+
Given a RAML document:
|
25
|
+
|
26
|
+
resources do
|
27
|
+
home "http://rubyworks.github.com/raml"
|
28
|
+
docs "http://rubyworks.github.com/raml/docs/api"
|
29
|
+
wiki "http://wiki.rubyworks.github.com/raml"
|
30
|
+
end
|
31
|
+
|
32
|
+
We get a two layer hash.
|
33
|
+
|
34
|
+
data = RAML.eval(@text)
|
35
|
+
|
36
|
+
data[:resources][:home].assert == "http://rubyworks.github.com/raml"
|
37
|
+
data[:resources][:docs].assert == "http://rubyworks.github.com/raml/docs/api"
|
38
|
+
data[:resources][:wiki].assert == "http://wiki.rubyworks.github.com/raml"
|
39
|
+
|
40
|
+
RAML is also considers the content of a block. If it is a scalar entry,
|
41
|
+
such as a String, then that will be assigned to the key.
|
42
|
+
|
43
|
+
Given a RAML document:
|
44
|
+
|
45
|
+
description %{
|
46
|
+
This is a description.
|
47
|
+
It can have multiple lines.
|
48
|
+
RAML handles this just fine,
|
49
|
+
because Ruby does too.
|
50
|
+
}
|
51
|
+
|
52
|
+
Loading this document, description will contain the text as expected.
|
53
|
+
|
54
|
+
data = RAML.eval(@text)
|
55
|
+
|
56
|
+
text = data[:description].sub(/\s+/, ' ').strip
|
57
|
+
|
58
|
+
text.assert.start_with?("This is")
|
59
|
+
text.assert.end_with?("does too.")
|
60
|
+
|
61
|
+
It is only unfortunate that Ruby doesn't have a margin controlled string
|
62
|
+
notation (e.g. `%L{ }`) so that post processing with `sub()` would not
|
63
|
+
be neccessary.
|
64
|
+
|
65
|
+
RAML has some options that makes it more flexible than many other data
|
66
|
+
lanaguages. For instance, it can allow for multi-key entries.
|
67
|
+
|
68
|
+
Given a RAML document:
|
69
|
+
|
70
|
+
source "http://rubygems.org"
|
71
|
+
gem "facets", "~> 2.8"
|
72
|
+
gem "ansi", "~> 1.1"
|
73
|
+
|
74
|
+
We simply need to inform the loader to allow identical keys.
|
75
|
+
|
76
|
+
data = RAML.eval(@text, :multikey=>true)
|
77
|
+
|
78
|
+
data.assert == {
|
79
|
+
:source=>"http://rubygems.org",
|
80
|
+
:gem=>[["facets", "~> 2.8"],["ansi", "~> 1.1"]]
|
81
|
+
}
|
82
|
+
|
83
|
+
If we did not turn on the multi-key option, then the last `gem` entry
|
84
|
+
would have simply overwritten the former.
|
85
|
+
|
86
|
+
data = RAML.eval(@text)
|
87
|
+
|
88
|
+
data.assert == {
|
89
|
+
:source=>"http://rubygems.org",
|
90
|
+
:gem=>["ansi", "~> 1.1"]
|
91
|
+
}
|
92
|
+
|
93
|
+
Not let's show-off the benefit of using RAML.eval instead of RAML.load.
|
94
|
+
|
95
|
+
Given a RAML document:
|
96
|
+
|
97
|
+
sum 1 + 1
|
98
|
+
|
99
|
+
We will see that the value of `sum` will be evaluated as 2.
|
100
|
+
|
101
|
+
data = RAML.eval(@text)
|
102
|
+
|
103
|
+
data.assert == {:sum=>2}
|
104
|
+
|
105
|
+
|
106
|
+
= RAML.read
|
107
|
+
|
108
|
+
The RAML.read() method parses a RAML document using Ripper.
|
109
|
+
In this way a RAML document is treated purely as data and cannot
|
110
|
+
contain any Ruby scripting.
|
111
|
+
|
112
|
+
Require the RAML library.
|
113
|
+
|
114
|
+
require 'raml'
|
115
|
+
|
116
|
+
Given a RAML document:
|
117
|
+
|
118
|
+
website "http://rubygems.org"
|
119
|
+
|
120
|
+
We can load the text via the #read method. (Note above document text has
|
121
|
+
been placed in the @text variable.)
|
122
|
+
|
123
|
+
data = RAML.read(@text)
|
124
|
+
|
125
|
+
data.assert == {:website=>"http://rubygems.org"}
|
126
|
+
|
127
|
+
One of the nicer features of RAML derives from Ruby's block notation, allowing
|
128
|
+
for nested entries.
|
129
|
+
|
130
|
+
Given a RAML document:
|
131
|
+
|
132
|
+
resources do
|
133
|
+
home "http://rubyworks.github.com/raml"
|
134
|
+
docs "http://rubyworks.github.com/raml/docs/api"
|
135
|
+
wiki "http://wiki.rubyworks.github.com/raml"
|
136
|
+
end
|
137
|
+
|
138
|
+
We get a two layer hash.
|
139
|
+
|
140
|
+
data = RAML.read(@text)
|
141
|
+
|
142
|
+
data[:resources][:home].assert == "http://rubyworks.github.com/raml"
|
143
|
+
data[:resources][:docs].assert == "http://rubyworks.github.com/raml/docs/api"
|
144
|
+
data[:resources][:wiki].assert == "http://wiki.rubyworks.github.com/raml"
|
145
|
+
|
146
|
+
RAML is also considers the content of a block. If it is a scalar entry,
|
147
|
+
such as a String, then that will be assigned to the key.
|
148
|
+
|
149
|
+
Given a RAML document:
|
150
|
+
|
151
|
+
description %{
|
152
|
+
This is a description.
|
153
|
+
It can have multiple lines.
|
154
|
+
RAML handles this just fine,
|
155
|
+
because Ruby does too.
|
156
|
+
}
|
157
|
+
|
158
|
+
Loading this document, description will contain the text as expected.
|
159
|
+
|
160
|
+
data = RAML.read(@text)
|
161
|
+
|
162
|
+
text = data[:description].sub(/\s+/, ' ').strip
|
163
|
+
|
164
|
+
text.assert.start_with?("This is")
|
165
|
+
text.assert.end_with?("does too.")
|
166
|
+
|
167
|
+
It is only unfortunate that Ruby doesn't have a margin controlled string
|
168
|
+
notation (e.g. `%L{ }`) so that post processing with `sub()` would not
|
169
|
+
be neccessary.
|
170
|
+
|
171
|
+
RAML has some options that makes it more flexible than many other data
|
172
|
+
lanaguages. For instance, it can allow for multi-key entries.
|
173
|
+
|
174
|
+
Given a RAML document:
|
175
|
+
|
176
|
+
source "http://rubygems.org"
|
177
|
+
gem "facets", "~> 2.8"
|
178
|
+
gem "ansi", "~> 1.1"
|
179
|
+
|
180
|
+
We simply need to inform the reader to allow identical keys.
|
181
|
+
|
182
|
+
data = RAML.read(@text, :multikey=>true)
|
183
|
+
|
184
|
+
data.assert == {
|
185
|
+
:source=>"http://rubygems.org",
|
186
|
+
:gem=>[["facets", "~> 2.8"],["ansi", "~> 1.1"]]
|
187
|
+
}
|
188
|
+
|
189
|
+
If we did not turn on the multi-key option, then the last `gem` entry
|
190
|
+
would have simply overwritten the former.
|
191
|
+
|
192
|
+
data = RAML.read(@text)
|
193
|
+
|
194
|
+
data.assert == {
|
195
|
+
:source=>"http://rubygems.org",
|
196
|
+
:gem=>["ansi", "~> 1.1"]
|
197
|
+
}
|
198
|
+
|
199
|
+
Not let's show-off the benefit of using RAML.read instead of RAML.eval.
|
200
|
+
|
201
|
+
Given a RAML document:
|
202
|
+
|
203
|
+
sum "word".upcase
|
204
|
+
|
205
|
+
We will see that the result of calling `#upcase` CANNOT be evaluated and
|
206
|
+
will raise an error.
|
207
|
+
|
208
|
+
expect Exception do
|
209
|
+
data = RAML.read(@text)
|
210
|
+
end if RUBY_VERSION >= '1.9'
|
211
|
+
|
212
|
+
Note, this last assertion is only true for Ruby 1.9+, becuase Ripper is
|
213
|
+
not supported by older versions of Ruby.
|
214
|
+
|
215
|
+
|
216
|
+
|
217
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
= Ruby Ambidextrous Meta-Language
|
2
|
+
|
3
|
+
{Homepage}[http://rubyworks.github.com/raml] |
|
4
|
+
{Source Code}[http://github.com/rubyworks/raml] |
|
5
|
+
{Mailing List}[http://googlegroups.com/group/rubyworks-mailinglist]
|
6
|
+
{IRC}[irc://chat.us.freenode.net/rubyworks]
|
7
|
+
|
8
|
+
{<img src="http://travis-ci.org/rubyworks/raml.png" />}[http://travis-ci.org/rubyworks/raml]
|
9
|
+
|
10
|
+
|
11
|
+
== DESCRIPTION
|
12
|
+
|
13
|
+
RAML is a flexable data format suitable for a variety of uses, such
|
14
|
+
as configuration files.
|
15
|
+
|
16
|
+
Admittedly, "Ruby Ambidextrous Meta-Language" is a funny name. But
|
17
|
+
nonetheless fitting, becuase unlike YAML, RAML can handle a wider
|
18
|
+
variety of data format design needs, even limited markup formats.
|
19
|
+
Unlike YAML, RAML is not a serialization language.
|
20
|
+
|
21
|
+
|
22
|
+
== SYNOPSIS
|
23
|
+
|
24
|
+
A RAML document is Ruby code operating under a set of open domain language rules.
|
25
|
+
An example RAML document looks like this:
|
26
|
+
|
27
|
+
source "http://rubygems.org"
|
28
|
+
example "this", 10, true
|
29
|
+
another do
|
30
|
+
name "Tonto"
|
31
|
+
age 42
|
32
|
+
weight 229
|
33
|
+
end
|
34
|
+
|
35
|
+
Loading this document in via RAML would produce the following Hash:
|
36
|
+
|
37
|
+
{:source=>"http://rubygems.org",
|
38
|
+
:example=>["this", 10, true],
|
39
|
+
:another=>{:name=>"Tonto", :age=>42, :weight=>229}}
|
40
|
+
|
41
|
+
Loading is handled by the `RAML.load` method. The method can take a string,
|
42
|
+
|
43
|
+
RAML.load("name 'Bob'")
|
44
|
+
|
45
|
+
Or an IO object,
|
46
|
+
|
47
|
+
RAML.load(File.new('foo.rml'))
|
48
|
+
|
49
|
+
The method also takes an `:safe` option that is used to set the level evaluation
|
50
|
+
Ruby is allowed. If the option is `false`, the default, than evaluation is handled
|
51
|
+
with Ruby `$SAFE=0`. If `true` the $SAFE=4.
|
52
|
+
|
53
|
+
RAML.load(raml, :safe=>true)
|
54
|
+
|
55
|
+
Safe evaluation is useful when loading untrusted data files. With `$SAFE=4`
|
56
|
+
most (though not all) security concerns are mitigated.
|
57
|
+
|
58
|
+
For a complete lockdown on evaluation, allowing only data setting and no other
|
59
|
+
forms of Ruby evaluation, `RAML.load` supports the `:eval` option. By default
|
60
|
+
it is `true`. By setting it to `false` (not `nil`), all code evaluation
|
61
|
+
can be turned off.
|
62
|
+
|
63
|
+
RAML.load(raml, :eval=>false)
|
64
|
+
|
65
|
+
Under the hood the current implementation has two different parsers, a
|
66
|
+
Ripper-based parser and a Kernel.eval based parser. By setting `:eval=>false`
|
67
|
+
the Ripper parser is used rather than the regular eval parser.
|
68
|
+
|
69
|
+
For additional examples and details on working with RAML files, see
|
70
|
+
the QED demonstrandum.
|
71
|
+
|
72
|
+
|
73
|
+
== IMPORTANT NOTE
|
74
|
+
|
75
|
+
The Ripper based parser is not yet robust and is NOT RECOMMENDED FOR PRODUCTION
|
76
|
+
USE, as it will parse invalid RAML documents without complaint. The eval parser
|
77
|
+
on the other hand works well.
|
78
|
+
|
79
|
+
|
80
|
+
== SPECIAL THANKS
|
81
|
+
|
82
|
+
Big props to <b>Robert Dober</b> for taking the time to help me improve
|
83
|
+
the code.
|
84
|
+
|
85
|
+
|
86
|
+
== COPYRIGHTS
|
87
|
+
|
88
|
+
Copyright (c) 2010 Rubyworks
|
89
|
+
|
90
|
+
RAML is distributed under the terms of the *FreeBSD* License.
|
91
|
+
See COPYING.rdoc for details.
|
92
|
+
|
data/lib/raml.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'raml/eval_parser'
|
2
|
+
|
3
|
+
if RUBY_VERSION > '1.9'
|
4
|
+
require 'raml/ripper_parser'
|
5
|
+
end
|
6
|
+
|
7
|
+
module RAML
|
8
|
+
|
9
|
+
# Load a RAML document. Like `eval()` but parses the document
|
10
|
+
# via Ripper, ensuring a pure data format.
|
11
|
+
#
|
12
|
+
# IMPORTANT: Ruby 1.8.x and older does not support Ripper.
|
13
|
+
# In this case RAML falls back to using `eval()` with $SAFE = 4.
|
14
|
+
#
|
15
|
+
# Arguments
|
16
|
+
#
|
17
|
+
# io - a String, File or any object that responds to #read.
|
18
|
+
#
|
19
|
+
# Options
|
20
|
+
#
|
21
|
+
# :eval - false for data-only parser
|
22
|
+
# :safe - true sets $SAFE=4
|
23
|
+
# :keep - public methods to keep in scope
|
24
|
+
# :scope - an object to act as the evaluation context
|
25
|
+
# :multikey - handle duplicate keys
|
26
|
+
#
|
27
|
+
# Returns [Hash] data parsed from document.
|
28
|
+
def self.load(io, options={})
|
29
|
+
if FalseClass === options[:eval]
|
30
|
+
read(io, options)
|
31
|
+
else
|
32
|
+
eval(io, options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Evaluate a RAML document. Like `load()` but parses the document via #eval.
|
37
|
+
# (same as load with :eval=>true). This can be done a $SAFE level 4 by
|
38
|
+
# setting the :safe option to +true+.
|
39
|
+
#
|
40
|
+
# Arguments
|
41
|
+
#
|
42
|
+
# io - a String, File or any object that responds to #read.
|
43
|
+
#
|
44
|
+
# Options
|
45
|
+
#
|
46
|
+
# :safe - true/false
|
47
|
+
# :keep - public methods to keep in scope
|
48
|
+
# :scope - an object to act as the evaluation context
|
49
|
+
# :multikey - handle duplicate keys
|
50
|
+
#
|
51
|
+
# Returns [Hash] data parsed from document.
|
52
|
+
def self.eval(io, options={})
|
53
|
+
code, file = io(io)
|
54
|
+
parser = RAML::EvalParser.new(options)
|
55
|
+
parser.parse(code, file)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Read in a RAML document. Like `load()` but parses the document via Ripper
|
59
|
+
# (same as load with :eval=>false). This only work in Ruby 1.9+, otherwise it
|
60
|
+
# falls back to the eval parer with `:safe=>true`.
|
61
|
+
#
|
62
|
+
# Arguments
|
63
|
+
#
|
64
|
+
# io - a String, File or any object that responds to #read.
|
65
|
+
#
|
66
|
+
# Options
|
67
|
+
#
|
68
|
+
# :keep - public methods to keep in scope
|
69
|
+
# :scope - an object to act as the evaluation context
|
70
|
+
# :multikey - handle duplicate keys
|
71
|
+
#
|
72
|
+
# Returns [Hash] data parsed from document.
|
73
|
+
def self.read(io, options={})
|
74
|
+
code, file = io(io)
|
75
|
+
if RUBY_VERSION > '1.9'
|
76
|
+
parser = RAML::RipperParser.new(options)
|
77
|
+
else
|
78
|
+
options[:safe] = true
|
79
|
+
parser = RAML::EvalParser.new(options)
|
80
|
+
end
|
81
|
+
parser.parse(code, file)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Take a String, File, IO or any object that respons to #read
|
87
|
+
# and return the string or result of calling #read and the
|
88
|
+
# file name if any and "(eval)" if not.
|
89
|
+
#
|
90
|
+
# Arguments
|
91
|
+
#
|
92
|
+
# io - a String, File or any object that responds to #read.
|
93
|
+
#
|
94
|
+
# Returns [String, String] text of string or file and file name or "(eval)".
|
95
|
+
def self.io(io)
|
96
|
+
case io
|
97
|
+
when String
|
98
|
+
file = '(eval)'
|
99
|
+
code = io
|
100
|
+
when File
|
101
|
+
file = io.path
|
102
|
+
code = io.read
|
103
|
+
else #IO
|
104
|
+
file = '(eval)'
|
105
|
+
code = io.read
|
106
|
+
end
|
107
|
+
return code, file
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
data/lib/raml.yml
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
---
|
2
|
+
source:
|
3
|
+
- meta
|
4
|
+
authors:
|
5
|
+
- name: 7rans
|
6
|
+
email: transfire@gmail.com
|
7
|
+
copyrights:
|
8
|
+
- holder: Rubyworks
|
9
|
+
year: '2010'
|
10
|
+
replacements: []
|
11
|
+
alternatives: []
|
12
|
+
requirements:
|
13
|
+
- name: blankslate
|
14
|
+
- name: detroit
|
15
|
+
groups:
|
16
|
+
- build
|
17
|
+
development: true
|
18
|
+
- name: qed
|
19
|
+
groups:
|
20
|
+
- test
|
21
|
+
development: true
|
22
|
+
dependencies: []
|
23
|
+
conflicts: []
|
24
|
+
repositories: []
|
25
|
+
resources:
|
26
|
+
home: http://rubyworks.github.com/raml
|
27
|
+
code: http://github.com/rubyworks/raml
|
28
|
+
docs: http://rubydoc.info/gems/raml/frames
|
29
|
+
mail: http://groups.google.com/group/rubyworks-mailinglist
|
30
|
+
gems: http://rubygems.org/gems/raml
|
31
|
+
extra: {}
|
32
|
+
load_path:
|
33
|
+
- lib
|
34
|
+
revision: 0
|
35
|
+
created: '2010-09-21'
|
36
|
+
summary: Ruby Syntax Data Language
|
37
|
+
title: RAML
|
38
|
+
version: 0.2.0
|
39
|
+
name: raml
|
40
|
+
description: RAML is a Ruby-syntax-based data language.
|
41
|
+
organization: rubyworks
|
42
|
+
date: '2011-10-28'
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'raml/multi_value'
|
3
|
+
|
4
|
+
unless defined?(::BasicObject)
|
5
|
+
require 'blankslate'
|
6
|
+
BasicObject = BlankSlate
|
7
|
+
end
|
8
|
+
|
9
|
+
module RAML
|
10
|
+
|
11
|
+
# The EvalParser parses RAML documents using standard Ruby evaluation.
|
12
|
+
# This has some limitations, but also some benefits.
|
13
|
+
#
|
14
|
+
# Unlike the pure data evaluator, the ruby evaluator can be instructed to
|
15
|
+
# keep methods available for access, as well as use a custom scope.
|
16
|
+
#
|
17
|
+
class EvalParser
|
18
|
+
|
19
|
+
#
|
20
|
+
SAFE = 4
|
21
|
+
|
22
|
+
# Need tainted data store.
|
23
|
+
HASH = {}.taint
|
24
|
+
|
25
|
+
#
|
26
|
+
attr :options
|
27
|
+
|
28
|
+
# You can pass in an object to act as the scope. All non-essential public
|
29
|
+
# and private Object methods will be removed from the scope unless a `keep`
|
30
|
+
# string or regex matches the name. Protected methods are also kept intact.
|
31
|
+
def initialize(options={})
|
32
|
+
@options = options
|
33
|
+
|
34
|
+
self.safe = options[:safe]
|
35
|
+
#self.file = options[:file]
|
36
|
+
self.keep = options[:keep]
|
37
|
+
self.scope = options[:scope] || BasicObject.new
|
38
|
+
self.multi_key = options[:multikey]
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
def safe?
|
43
|
+
@safe
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
def safe=(boolean)
|
48
|
+
@safe = !!boolean
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns 4 is safe is true, otherwise 0.
|
52
|
+
def safe_level
|
53
|
+
safe? ? 4 : 0
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns Array<Regexp>.
|
57
|
+
attr_reader :keep
|
58
|
+
|
59
|
+
def keep=(list)
|
60
|
+
@keep = [list].compact.flatten
|
61
|
+
end
|
62
|
+
|
63
|
+
## Returns [String] file name.
|
64
|
+
#attr_accessor :file
|
65
|
+
|
66
|
+
# Returns [Boolean] true/false.
|
67
|
+
def multi_key?
|
68
|
+
@multi_key
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
def multi_key=(bool)
|
73
|
+
@multi_key = !!bool
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns [BasicObject,Object] scope object.
|
77
|
+
attr_reader :scope
|
78
|
+
|
79
|
+
# Sets the scope object while preparing it for use as the evaluation
|
80
|
+
# context.
|
81
|
+
def scope=(object)
|
82
|
+
@scope ||= (
|
83
|
+
#qua_class = (class << object; self; end)
|
84
|
+
#methods = [object.public_methods, Object.private_instance_methods].flatten
|
85
|
+
#methods.each do |m|
|
86
|
+
# next if /^(__|instance_|singleton_method_|binding$|method_missing$|extend$|initialize$|object_id$|p$)/ =~ m.to_s
|
87
|
+
# next if keep.any?{ |k| k === m.to_s }
|
88
|
+
# qua_class.__send__(:undef_method, m)
|
89
|
+
#end
|
90
|
+
parser = self
|
91
|
+
object.instance_eval{ @__parser__ = parser }
|
92
|
+
#object.instance_eval{ extend MethodMissing }
|
93
|
+
MethodMissing.__send__(:extend_object, object)
|
94
|
+
object
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
def parse(code=nil, file=nil, &block)
|
100
|
+
data = HASH.dup
|
101
|
+
|
102
|
+
scope.instance_eval{ @__data__ = data}
|
103
|
+
|
104
|
+
result = nil
|
105
|
+
|
106
|
+
thread = Thread.new do
|
107
|
+
$SAFE = safe_level unless $SAFE == safe_level
|
108
|
+
result = if block
|
109
|
+
scope.instance_eval(&block)
|
110
|
+
else
|
111
|
+
scope.instance_eval(code, file)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
thread.join
|
116
|
+
|
117
|
+
return result if data.empty? # good idea?
|
118
|
+
return data
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
module MethodMissing
|
123
|
+
#
|
124
|
+
def method_missing(name, *args, &block)
|
125
|
+
return @__data__[name] if args.empty? and !block
|
126
|
+
if block
|
127
|
+
val = EvalParser.new(@__parser__.options).parse(&block)
|
128
|
+
else
|
129
|
+
val = args.size == 1 ? args.first : args
|
130
|
+
end
|
131
|
+
if @__parser__.multi_key?
|
132
|
+
if @__data__.key?(name)
|
133
|
+
unless MultiValue === @__data__[name]
|
134
|
+
@__data__[name] = MultiValue.new(@__data__[name])
|
135
|
+
end
|
136
|
+
@__data__[name] << val
|
137
|
+
else
|
138
|
+
@__data__[name] = val
|
139
|
+
end
|
140
|
+
else
|
141
|
+
@__data__[name] = val
|
142
|
+
val
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'ripper'
|
2
|
+
require 'pp'
|
3
|
+
require 'raml/multi_value'
|
4
|
+
|
5
|
+
module RAML
|
6
|
+
|
7
|
+
# RAML document parser utilizoing Ripper.
|
8
|
+
#
|
9
|
+
# NOTE: This code is probably far from robust and is almost certainly not
|
10
|
+
# best the approach to implmentation. But your humble author is no expert
|
11
|
+
# on Ripper or parsers in general.
|
12
|
+
#
|
13
|
+
# FIXME: This class needs work. I currently handles basic cases, but will
|
14
|
+
# incorrectly parse complex cases.
|
15
|
+
#
|
16
|
+
# FIXME: Add non hash block value support.
|
17
|
+
class RipperParser
|
18
|
+
|
19
|
+
def initialize(options={})
|
20
|
+
@options = options
|
21
|
+
|
22
|
+
self.multi_key = options[:multikey]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns [Boolean] true/false.
|
26
|
+
def multi_key?
|
27
|
+
@multi_key
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set multi-key option.
|
31
|
+
def multi_key=(bool)
|
32
|
+
@multi_key = !!bool
|
33
|
+
end
|
34
|
+
|
35
|
+
# Parse the RAML document via Ripper.
|
36
|
+
def parse(code, file=nil)
|
37
|
+
tree = Ripper::SexpBuilder.new(code).parse
|
38
|
+
|
39
|
+
@k, @v = nil, []
|
40
|
+
|
41
|
+
d = clean(tree)
|
42
|
+
set(d)
|
43
|
+
|
44
|
+
return d
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
#
|
50
|
+
def clean(tree, data={})
|
51
|
+
d = data
|
52
|
+
|
53
|
+
tag, *rest = *tree
|
54
|
+
|
55
|
+
#show(tag, rest)
|
56
|
+
|
57
|
+
case tag.to_s
|
58
|
+
when "@ident"
|
59
|
+
set(d)
|
60
|
+
@k = rest.shift
|
61
|
+
when "@kw"
|
62
|
+
case rest.shift
|
63
|
+
when "nil" then @v << nil
|
64
|
+
when "true" then @v << true
|
65
|
+
when "false" then @v << false
|
66
|
+
end
|
67
|
+
when "@int"
|
68
|
+
@v << rest.shift.to_i
|
69
|
+
when "@float"
|
70
|
+
@v << rest.shift.to_f
|
71
|
+
when /^@/
|
72
|
+
@v << rest.shift
|
73
|
+
when "do_block"
|
74
|
+
h = [d, @k, @v]
|
75
|
+
@k, @v = nil, []
|
76
|
+
n = {}
|
77
|
+
rest.each do |r|
|
78
|
+
clean(r, n)
|
79
|
+
end
|
80
|
+
set(n)
|
81
|
+
d, @k, @v = *h
|
82
|
+
@v << n
|
83
|
+
set(d)
|
84
|
+
when '.'
|
85
|
+
raise SyntaxError, "evaluations forbidden"
|
86
|
+
else
|
87
|
+
rest.each do |r|
|
88
|
+
clean(r, d)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
return d
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
def set(data)
|
97
|
+
return unless @k
|
98
|
+
if multi_key?
|
99
|
+
set_multi_key(data)
|
100
|
+
else
|
101
|
+
set_key(data)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
def set_key(data)
|
107
|
+
key = @k.to_sym
|
108
|
+
case @v.size
|
109
|
+
when 0
|
110
|
+
data[key] = nil
|
111
|
+
when 1
|
112
|
+
data[key] = @v.first
|
113
|
+
else
|
114
|
+
data[key] = @v
|
115
|
+
end
|
116
|
+
@k, @v = nil, []
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
def set_multi_key(data)
|
121
|
+
key = @k.to_sym
|
122
|
+
|
123
|
+
if data.key?(key)
|
124
|
+
unless MultiValue === data[key]
|
125
|
+
data[key] = MultiValue.new(data[key])
|
126
|
+
end
|
127
|
+
|
128
|
+
case @v.size
|
129
|
+
when 1
|
130
|
+
data[key] << @v.first
|
131
|
+
else
|
132
|
+
data[key] << @v
|
133
|
+
end
|
134
|
+
@k, @v = nil, []
|
135
|
+
else
|
136
|
+
set_key(data)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Used for development purposes only.
|
141
|
+
def show(name, args)
|
142
|
+
if @options[:debug]
|
143
|
+
puts "#{name}:"
|
144
|
+
p args
|
145
|
+
puts
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
data/qed/eval.rdoc
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
= RAML.eval
|
2
|
+
|
3
|
+
The RAML.eval() method parses a RAML document using the Kernel.eval.
|
4
|
+
In this way Ruby scripting can still be utilized within the document.
|
5
|
+
|
6
|
+
Require the RAML library.
|
7
|
+
|
8
|
+
require 'raml'
|
9
|
+
|
10
|
+
Given a RAML document:
|
11
|
+
|
12
|
+
website "http://rubygems.org"
|
13
|
+
|
14
|
+
We can load the text via the #load method. (Note above document text has
|
15
|
+
been placed in the @text variable.)
|
16
|
+
|
17
|
+
data = RAML.eval(@text)
|
18
|
+
|
19
|
+
data.assert == {:website=>"http://rubygems.org"}
|
20
|
+
|
21
|
+
One of the nicer features of RAML derives from Ruby's block notation, allowing
|
22
|
+
for nested entries.
|
23
|
+
|
24
|
+
Given a RAML document:
|
25
|
+
|
26
|
+
resources do
|
27
|
+
home "http://rubyworks.github.com/raml"
|
28
|
+
docs "http://rubyworks.github.com/raml/docs/api"
|
29
|
+
wiki "http://wiki.rubyworks.github.com/raml"
|
30
|
+
end
|
31
|
+
|
32
|
+
We get a two layer hash.
|
33
|
+
|
34
|
+
data = RAML.eval(@text)
|
35
|
+
|
36
|
+
data[:resources][:home].assert == "http://rubyworks.github.com/raml"
|
37
|
+
data[:resources][:docs].assert == "http://rubyworks.github.com/raml/docs/api"
|
38
|
+
data[:resources][:wiki].assert == "http://wiki.rubyworks.github.com/raml"
|
39
|
+
|
40
|
+
RAML is also considers the content of a block. If it is a scalar entry,
|
41
|
+
such as a String, then that will be assigned to the key.
|
42
|
+
|
43
|
+
Given a RAML document:
|
44
|
+
|
45
|
+
description %{
|
46
|
+
This is a description.
|
47
|
+
It can have multiple lines.
|
48
|
+
RAML handles this just fine,
|
49
|
+
because Ruby does too.
|
50
|
+
}
|
51
|
+
|
52
|
+
Loading this document, description will contain the text as expected.
|
53
|
+
|
54
|
+
data = RAML.eval(@text)
|
55
|
+
|
56
|
+
text = data[:description].sub(/\s+/, ' ').strip
|
57
|
+
|
58
|
+
text.assert.start_with?("This is")
|
59
|
+
text.assert.end_with?("does too.")
|
60
|
+
|
61
|
+
It is only unfortunate that Ruby doesn't have a margin controlled string
|
62
|
+
notation (e.g. `%L{ }`) so that post processing with `sub()` would not
|
63
|
+
be neccessary.
|
64
|
+
|
65
|
+
RAML has some options that makes it more flexible than many other data
|
66
|
+
lanaguages. For instance, it can allow for multi-key entries.
|
67
|
+
|
68
|
+
Given a RAML document:
|
69
|
+
|
70
|
+
source "http://rubygems.org"
|
71
|
+
gem "facets", "~> 2.8"
|
72
|
+
gem "ansi", "~> 1.1"
|
73
|
+
|
74
|
+
We simply need to inform the loader to allow identical keys.
|
75
|
+
|
76
|
+
data = RAML.eval(@text, :multikey=>true)
|
77
|
+
|
78
|
+
data.assert == {
|
79
|
+
:source=>"http://rubygems.org",
|
80
|
+
:gem=>[["facets", "~> 2.8"],["ansi", "~> 1.1"]]
|
81
|
+
}
|
82
|
+
|
83
|
+
If we did not turn on the multi-key option, then the last `gem` entry
|
84
|
+
would have simply overwritten the former.
|
85
|
+
|
86
|
+
data = RAML.eval(@text)
|
87
|
+
|
88
|
+
data.assert == {
|
89
|
+
:source=>"http://rubygems.org",
|
90
|
+
:gem=>["ansi", "~> 1.1"]
|
91
|
+
}
|
92
|
+
|
93
|
+
Not let's show-off the benefit of using RAML.eval instead of RAML.load.
|
94
|
+
|
95
|
+
Given a RAML document:
|
96
|
+
|
97
|
+
sum 1 + 1
|
98
|
+
|
99
|
+
We will see that the value of `sum` will be evaluated as 2.
|
100
|
+
|
101
|
+
data = RAML.eval(@text)
|
102
|
+
|
103
|
+
data.assert == {:sum=>2}
|
104
|
+
|
data/qed/read.rdoc
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
= RAML.read
|
2
|
+
|
3
|
+
The RAML.read() method parses a RAML document using Ripper.
|
4
|
+
In this way a RAML document is treated purely as data and cannot
|
5
|
+
contain any Ruby scripting.
|
6
|
+
|
7
|
+
Require the RAML library.
|
8
|
+
|
9
|
+
require 'raml'
|
10
|
+
|
11
|
+
Given a RAML document:
|
12
|
+
|
13
|
+
website "http://rubygems.org"
|
14
|
+
|
15
|
+
We can load the text via the #read method. (Note above document text has
|
16
|
+
been placed in the @text variable.)
|
17
|
+
|
18
|
+
data = RAML.read(@text)
|
19
|
+
|
20
|
+
data.assert == {:website=>"http://rubygems.org"}
|
21
|
+
|
22
|
+
One of the nicer features of RAML derives from Ruby's block notation, allowing
|
23
|
+
for nested entries.
|
24
|
+
|
25
|
+
Given a RAML document:
|
26
|
+
|
27
|
+
resources do
|
28
|
+
home "http://rubyworks.github.com/raml"
|
29
|
+
docs "http://rubyworks.github.com/raml/docs/api"
|
30
|
+
wiki "http://wiki.rubyworks.github.com/raml"
|
31
|
+
end
|
32
|
+
|
33
|
+
We get a two layer hash.
|
34
|
+
|
35
|
+
data = RAML.read(@text)
|
36
|
+
|
37
|
+
data[:resources][:home].assert == "http://rubyworks.github.com/raml"
|
38
|
+
data[:resources][:docs].assert == "http://rubyworks.github.com/raml/docs/api"
|
39
|
+
data[:resources][:wiki].assert == "http://wiki.rubyworks.github.com/raml"
|
40
|
+
|
41
|
+
RAML is also considers the content of a block. If it is a scalar entry,
|
42
|
+
such as a String, then that will be assigned to the key.
|
43
|
+
|
44
|
+
Given a RAML document:
|
45
|
+
|
46
|
+
description %{
|
47
|
+
This is a description.
|
48
|
+
It can have multiple lines.
|
49
|
+
RAML handles this just fine,
|
50
|
+
because Ruby does too.
|
51
|
+
}
|
52
|
+
|
53
|
+
Loading this document, description will contain the text as expected.
|
54
|
+
|
55
|
+
data = RAML.read(@text)
|
56
|
+
|
57
|
+
text = data[:description].sub(/\s+/, ' ').strip
|
58
|
+
|
59
|
+
text.assert.start_with?("This is")
|
60
|
+
text.assert.end_with?("does too.")
|
61
|
+
|
62
|
+
It is only unfortunate that Ruby doesn't have a margin controlled string
|
63
|
+
notation (e.g. `%L{ }`) so that post processing with `sub()` would not
|
64
|
+
be neccessary.
|
65
|
+
|
66
|
+
RAML has some options that makes it more flexible than many other data
|
67
|
+
lanaguages. For instance, it can allow for multi-key entries.
|
68
|
+
|
69
|
+
Given a RAML document:
|
70
|
+
|
71
|
+
source "http://rubygems.org"
|
72
|
+
gem "facets", "~> 2.8"
|
73
|
+
gem "ansi", "~> 1.1"
|
74
|
+
|
75
|
+
We simply need to inform the reader to allow identical keys.
|
76
|
+
|
77
|
+
data = RAML.read(@text, :multikey=>true)
|
78
|
+
|
79
|
+
data.assert == {
|
80
|
+
:source=>"http://rubygems.org",
|
81
|
+
:gem=>[["facets", "~> 2.8"],["ansi", "~> 1.1"]]
|
82
|
+
}
|
83
|
+
|
84
|
+
If we did not turn on the multi-key option, then the last `gem` entry
|
85
|
+
would have simply overwritten the former.
|
86
|
+
|
87
|
+
data = RAML.read(@text)
|
88
|
+
|
89
|
+
data.assert == {
|
90
|
+
:source=>"http://rubygems.org",
|
91
|
+
:gem=>["ansi", "~> 1.1"]
|
92
|
+
}
|
93
|
+
|
94
|
+
Not let's show-off the benefit of using RAML.read instead of RAML.eval.
|
95
|
+
|
96
|
+
Given a RAML document:
|
97
|
+
|
98
|
+
sum "word".upcase
|
99
|
+
|
100
|
+
We will see that the result of calling `#upcase` CANNOT be evaluated and
|
101
|
+
will raise an error.
|
102
|
+
|
103
|
+
expect Exception do
|
104
|
+
data = RAML.read(@text)
|
105
|
+
end if RUBY_VERSION >= '1.9'
|
106
|
+
|
107
|
+
Note, this last assertion is only true for Ruby 1.9+, becuase Ripper is
|
108
|
+
not supported by older versions of Ruby.
|
109
|
+
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: raml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- 7rans
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: blankslate
|
16
|
+
requirement: &22824260 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *22824260
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: detroit
|
27
|
+
requirement: &22823580 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *22823580
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: qed
|
38
|
+
requirement: &22822940 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *22822940
|
47
|
+
description: RAML is a Ruby-syntax-based data language.
|
48
|
+
email:
|
49
|
+
- transfire@gmail.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files:
|
53
|
+
- HISTORY.rdoc
|
54
|
+
- README.rdoc
|
55
|
+
- QED.rdoc
|
56
|
+
- COPYING.rdoc
|
57
|
+
files:
|
58
|
+
- .ruby
|
59
|
+
- .yardopts
|
60
|
+
- lib/raml/core_ext.rb
|
61
|
+
- lib/raml/eval_parser.rb
|
62
|
+
- lib/raml/multi_value.rb
|
63
|
+
- lib/raml/ripper_parser.rb
|
64
|
+
- lib/raml.rb
|
65
|
+
- lib/raml.yml
|
66
|
+
- qed/applique/document.rb
|
67
|
+
- qed/eval.rdoc
|
68
|
+
- qed/read.rdoc
|
69
|
+
- qed/samples/sample1.rml
|
70
|
+
- qed/samples/sample2.rml
|
71
|
+
- HISTORY.rdoc
|
72
|
+
- README.rdoc
|
73
|
+
- QED.rdoc
|
74
|
+
- COPYING.rdoc
|
75
|
+
homepage: http://rubyworks.github.com/raml
|
76
|
+
licenses: []
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 1.8.10
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Ruby Syntax Data Language
|
99
|
+
test_files: []
|