raml 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|