yourdsl 0.7.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/.gitignore +3 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +19 -0
- data/README.md +106 -0
- data/Rakefile +14 -0
- data/example/feature.rb +82 -0
- data/lib/yourdsl.rb +74 -0
- data/test/yourdsl_test.rb +154 -0
- data/yourdsl.gemspec +21 -0
- metadata +57 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2011 Ryan Allen, Envato Pty Ltd
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# YourDSL
|
2
|
+
|
3
|
+
## Assumptions.
|
4
|
+
|
5
|
+
* People love libraries with DSLs like Sinatra and ActiveRecord and Babushka and AASM and (name your favourite Ruby library).
|
6
|
+
* What they love about these is the small amount of Ruby syntax required to get a whole lot done.
|
7
|
+
* They love that they can contextualise their definitions (that make the libraries do things) with natural Ruby syntax such as blocks.
|
8
|
+
* To enable these kinds of libraries the use of so-called 'meta-programming' constructs are required (instance_eval, instance_exec).
|
9
|
+
* Clever but inexperienced Ruby programmers often make very useful libraries with wonderful APIs but horrible internals
|
10
|
+
|
11
|
+
## Goals.
|
12
|
+
|
13
|
+
* Decouple the language definition of an internal DSL from its implementation
|
14
|
+
* Allow library authors to dream up APIs and implement them without entering Ruby metaprogramming hell (it is a real place).
|
15
|
+
|
16
|
+
## Example
|
17
|
+
class Feature < Test::Unit::TestCase
|
18
|
+
# Configuring lispy to geenrate an AST for our language
|
19
|
+
|
20
|
+
PROC_KEYWORDS = [:Given, :When, :Then, :And]
|
21
|
+
KEYWORDS = [:Scenario, :Tag] + PROC_KEYWORDS
|
22
|
+
|
23
|
+
extend YourDSL
|
24
|
+
record_your_dsl :only => KEYWORDS, :retain_blocks_for => PROC_KEYWORDS
|
25
|
+
|
26
|
+
# Using our language
|
27
|
+
Scenario "this gets lispyified" do
|
28
|
+
Given "something" do
|
29
|
+
end
|
30
|
+
|
31
|
+
Then "test something exists" do
|
32
|
+
fail "ohai"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Barfing out the AST for the above
|
38
|
+
require 'rubygems'
|
39
|
+
require 'awesome_print'
|
40
|
+
ap Feature.output
|
41
|
+
|
42
|
+
# Example 'interpreter' for the AST generated above
|
43
|
+
# Executes the block on the Given and Then from above sequentially
|
44
|
+
# Spike on how an acceptance testing DSL could work
|
45
|
+
Feature.class_eval do
|
46
|
+
def test_something
|
47
|
+
scenario = Feature.output.expressions.first
|
48
|
+
steps = scenario.scope.expressions
|
49
|
+
instance_eval &steps[0].proc
|
50
|
+
instance_eval &steps[1].proc
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
OUTPUTS:
|
55
|
+
➜ example git:(no_more_last_last_last) ✗ ruby feature.rb
|
56
|
+
{
|
57
|
+
:file => "feature.rb",
|
58
|
+
:expressions => [
|
59
|
+
[0] {
|
60
|
+
:symbol => :Scenario,
|
61
|
+
:args => "this gets lispyified",
|
62
|
+
:lineno => "14",
|
63
|
+
:proc => nil,
|
64
|
+
:scope => {
|
65
|
+
:expressions => [
|
66
|
+
[0] {
|
67
|
+
:symbol => :Given,
|
68
|
+
:args => "something",
|
69
|
+
:lineno => "15",
|
70
|
+
:proc => #<Proc:0x000001010e9140@feature.rb:15>,
|
71
|
+
:scope => nil
|
72
|
+
},
|
73
|
+
[1] {
|
74
|
+
:symbol => :Then,
|
75
|
+
:args => "test something exists",
|
76
|
+
:lineno => "18",
|
77
|
+
:proc => #<Proc:0x000001010e8ec0@feature.rb:18>,
|
78
|
+
:scope => nil
|
79
|
+
}
|
80
|
+
]
|
81
|
+
}
|
82
|
+
}
|
83
|
+
]
|
84
|
+
}
|
85
|
+
Loaded suite feature
|
86
|
+
Started
|
87
|
+
E
|
88
|
+
Finished in 0.006305 seconds.
|
89
|
+
|
90
|
+
1) Error:
|
91
|
+
test_something(Feature):
|
92
|
+
RuntimeError: ohai
|
93
|
+
feature.rb:19:in `block (2 levels) in <class:Feature>'
|
94
|
+
feature.rb:34:in `instance_eval'
|
95
|
+
feature.rb:34:in `test_something'
|
96
|
+
|
97
|
+
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
|
98
|
+
|
99
|
+
## Credits
|
100
|
+
|
101
|
+
* Lispy concept and original impl by Ryan Allen (http://github.com/ryan-allen/lispy)
|
102
|
+
* Rewritten and extended by Evan Light (http://github.com/elight/yourdsl)
|
103
|
+
|
104
|
+
## License.
|
105
|
+
|
106
|
+
Released under the MIT license (see MIT-LICENSE).
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
task :default do
|
5
|
+
Rake::Task['run_tests'].invoke
|
6
|
+
end
|
7
|
+
|
8
|
+
task :run_tests do
|
9
|
+
if RUBY_VERSION =~ /^1.9/
|
10
|
+
require_relative 'test/yourdsl_test'
|
11
|
+
else
|
12
|
+
require 'test/yourdsl_test'
|
13
|
+
end
|
14
|
+
end
|
data/example/feature.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
load '../lib/yourdsl.rb'
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class Feature < Test::Unit::TestCase
|
6
|
+
PROC_KEYWORDS = [:Given, :When, :Then, :And]
|
7
|
+
KEYWORDS = [:Scenario, :Tag] + PROC_KEYWORDS
|
8
|
+
|
9
|
+
extend YourDSL
|
10
|
+
record_your_dsl :only => KEYWORDS, :retain_blocks_for => PROC_KEYWORDS
|
11
|
+
|
12
|
+
# Everything after this gets lispyified
|
13
|
+
|
14
|
+
Scenario "this gets lispyified" do
|
15
|
+
Given "something" do
|
16
|
+
end
|
17
|
+
|
18
|
+
Then "test something exists" do
|
19
|
+
fail "ohai"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'awesome_print'
|
26
|
+
ap Feature.output
|
27
|
+
|
28
|
+
Feature.class_eval do
|
29
|
+
# manually execute "Given" and "Then"
|
30
|
+
def test_something
|
31
|
+
scenario = Feature.output.expressions.first
|
32
|
+
steps = scenario.scope.expressions
|
33
|
+
instance_eval &steps[0].proc
|
34
|
+
instance_eval &steps[1].proc
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# OUTPUTS:
|
39
|
+
# ➜ example git:(no_more_last_last_last) ✗ ruby feature.rb
|
40
|
+
# {
|
41
|
+
# :file => "feature.rb",
|
42
|
+
# :expressions => [
|
43
|
+
# [0] {
|
44
|
+
# :symbol => :Scenario,
|
45
|
+
# :args => "this gets lispyified",
|
46
|
+
# :lineno => "14",
|
47
|
+
# :proc => nil,
|
48
|
+
# :scope => {
|
49
|
+
# :expressions => [
|
50
|
+
# [0] {
|
51
|
+
# :symbol => :Given,
|
52
|
+
# :args => "something",
|
53
|
+
# :lineno => "15",
|
54
|
+
# :proc => #<Proc:0x000001010e9140@feature.rb:15>,
|
55
|
+
# :scope => nil
|
56
|
+
# },
|
57
|
+
# [1] {
|
58
|
+
# :symbol => :Then,
|
59
|
+
# :args => "test something exists",
|
60
|
+
# :lineno => "18",
|
61
|
+
# :proc => #<Proc:0x000001010e8ec0@feature.rb:18>,
|
62
|
+
# :scope => nil
|
63
|
+
# }
|
64
|
+
# ]
|
65
|
+
# }
|
66
|
+
# }
|
67
|
+
# ]
|
68
|
+
# }
|
69
|
+
# Loaded suite feature
|
70
|
+
# Started
|
71
|
+
# E
|
72
|
+
# Finished in 0.006305 seconds.
|
73
|
+
#
|
74
|
+
# 1) Error:
|
75
|
+
# test_something(Feature):
|
76
|
+
# RuntimeError: ohai
|
77
|
+
# feature.rb:19:in `block (2 levels) in <class:Feature>'
|
78
|
+
# feature.rb:34:in `instance_eval'
|
79
|
+
# feature.rb:34:in `test_something'
|
80
|
+
#
|
81
|
+
# 1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
|
82
|
+
#
|
data/lib/yourdsl.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module YourDSL
|
2
|
+
class Scope < Struct.new(:expressions); end
|
3
|
+
class Expression < Struct.new(:symbol, :args, :lineno, :proc, :scope); end
|
4
|
+
class Output < Struct.new(:file, :expressions); end
|
5
|
+
|
6
|
+
VERSION = '0.7.0'
|
7
|
+
|
8
|
+
METHODS_TO_KEEP = /^__/, /class/, /instance_/, /method_missing/, /object_id/
|
9
|
+
|
10
|
+
instance_methods.each do |m|
|
11
|
+
undef_method m unless METHODS_TO_KEEP.find { |r| r.match m }
|
12
|
+
end
|
13
|
+
|
14
|
+
def record_your_dsl(opts = {})
|
15
|
+
@@remember_blocks_starting_with = Array(opts[:retain_blocks_for])
|
16
|
+
@@only = Array(opts[:only])
|
17
|
+
@@exclude = Array(opts[:except])
|
18
|
+
@@output = Output.new
|
19
|
+
@@file = nil
|
20
|
+
@stack = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def output
|
24
|
+
if @current_scope
|
25
|
+
@@output.expressions = @current_scope.expressions
|
26
|
+
end
|
27
|
+
@@output
|
28
|
+
end
|
29
|
+
|
30
|
+
def file=(file)
|
31
|
+
unless @@file
|
32
|
+
@@file = file
|
33
|
+
@@output.file = @@file
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(sym, *args, &block)
|
38
|
+
caller[0] =~ (/(.*):(.*):in?/)
|
39
|
+
file, lineno = $1, $2
|
40
|
+
self.file = file
|
41
|
+
|
42
|
+
if !@@only.empty? && !@@only.include?(sym)
|
43
|
+
fail(NoMethodError, sym.to_s)
|
44
|
+
end
|
45
|
+
if !@@exclude.empty? && @@exclude.include?(sym)
|
46
|
+
fail(NoMethodError, sym.to_s)
|
47
|
+
end
|
48
|
+
|
49
|
+
args = (args.length == 1 ? args.first : args)
|
50
|
+
@current_scope ||= Scope.new([])
|
51
|
+
@current_scope.expressions << Expression.new(sym, args, lineno)
|
52
|
+
if block
|
53
|
+
# there is some simpler recursive way of doing this, will fix it shortly
|
54
|
+
if @@remember_blocks_starting_with.include? sym
|
55
|
+
@current_scope.expressions.last.proc = block
|
56
|
+
else
|
57
|
+
nest(&block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def nest(&block)
|
64
|
+
@stack.push @current_scope
|
65
|
+
|
66
|
+
new_scope = Scope.new([])
|
67
|
+
@current_scope.expressions.last.scope = new_scope
|
68
|
+
@current_scope = new_scope
|
69
|
+
|
70
|
+
instance_exec(&block)
|
71
|
+
|
72
|
+
@current_scope = @stack.pop
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'yourdsl'
|
3
|
+
|
4
|
+
class YourDSLTest < Test::Unit::TestCase
|
5
|
+
class Whatever
|
6
|
+
extend YourDSL
|
7
|
+
record_your_dsl
|
8
|
+
|
9
|
+
setup :workers => 30, :connections => 1024
|
10
|
+
http :access_log => :off do
|
11
|
+
server :listen => 80 do
|
12
|
+
location '/' do
|
13
|
+
doc_root '/var/www/website'
|
14
|
+
end
|
15
|
+
location '~ .php$' do
|
16
|
+
fcgi :port => 8877
|
17
|
+
script_root '/var/www/website'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
ohai
|
22
|
+
end
|
23
|
+
@@whatever = Whatever.output
|
24
|
+
|
25
|
+
class MoarYourDSL
|
26
|
+
extend YourDSL
|
27
|
+
record_your_dsl
|
28
|
+
|
29
|
+
setup
|
30
|
+
setup do
|
31
|
+
lol
|
32
|
+
lol do
|
33
|
+
hi
|
34
|
+
hi
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
@@moar_yourdsl = MoarYourDSL.output
|
39
|
+
|
40
|
+
class RetainBlocks
|
41
|
+
extend YourDSL
|
42
|
+
record_your_dsl :retain_blocks_for => [:Given, :When, :Then]
|
43
|
+
|
44
|
+
Scenario "My first awesome scenario" do
|
45
|
+
Given "teh shiznit" do
|
46
|
+
#shiznit
|
47
|
+
end
|
48
|
+
|
49
|
+
When "I do something" do
|
50
|
+
#komg.do_something
|
51
|
+
end
|
52
|
+
|
53
|
+
Then "this is pending"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
@@retain_blocks = RetainBlocks.output
|
57
|
+
|
58
|
+
begin
|
59
|
+
class OptInParsing
|
60
|
+
extend YourDSL
|
61
|
+
record_your_dsl :only => [:Foo]
|
62
|
+
|
63
|
+
Foo "bar" do
|
64
|
+
blech
|
65
|
+
end
|
66
|
+
end
|
67
|
+
rescue
|
68
|
+
@@opt_in_parsing_error = $!
|
69
|
+
end
|
70
|
+
|
71
|
+
begin
|
72
|
+
class OptOutParsing
|
73
|
+
extend YourDSL
|
74
|
+
record_your_dsl :except => [:blech]
|
75
|
+
|
76
|
+
Foo "bar" do
|
77
|
+
blech
|
78
|
+
end
|
79
|
+
end
|
80
|
+
rescue
|
81
|
+
@@opt_out_parsing_error = $!
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_yourdsl
|
85
|
+
expected = YourDSL::Output.new(__FILE__, [
|
86
|
+
YourDSL::Expression.new(:setup, {:workers=>30, :connections=>1024}, "9"),
|
87
|
+
YourDSL::Expression.new(:http, {:access_log =>:off}, "10", nil,
|
88
|
+
YourDSL::Scope.new.tap { |s1| s1.expressions = [
|
89
|
+
YourDSL::Expression.new(:server, {:listen=>80}, "11", nil,
|
90
|
+
YourDSL::Scope.new.tap { |s2| s2.expressions = [
|
91
|
+
YourDSL::Expression.new(:location, '/', "12", nil,
|
92
|
+
YourDSL::Scope.new.tap { |s3| s3.expressions = [
|
93
|
+
YourDSL::Expression.new(:doc_root, '/var/www/website', "13")
|
94
|
+
]}
|
95
|
+
),
|
96
|
+
YourDSL::Expression.new(:location, '~ .php$', "15", nil,
|
97
|
+
YourDSL::Scope.new.tap { |s4| s4.expressions = [
|
98
|
+
YourDSL::Expression.new(:fcgi, {:port => 8877}, "16"),
|
99
|
+
YourDSL::Expression.new(:script_root, '/var/www/website', "17")
|
100
|
+
]}
|
101
|
+
)
|
102
|
+
]}
|
103
|
+
)
|
104
|
+
]}
|
105
|
+
),
|
106
|
+
YourDSL::Expression.new(:ohai, [], "21")
|
107
|
+
])
|
108
|
+
assert_equal expected, @@whatever
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_moar_yourdsl
|
112
|
+
expected = YourDSL::Output.new(__FILE__, [
|
113
|
+
YourDSL::Expression.new(:setup, [], "29"),
|
114
|
+
YourDSL::Expression.new(:setup, [], "30", nil,
|
115
|
+
YourDSL::Scope.new.tap { |s1| s1.expressions = [
|
116
|
+
YourDSL::Expression.new(:lol, [], "31"),
|
117
|
+
YourDSL::Expression.new(:lol, [], "32", nil,
|
118
|
+
YourDSL::Scope.new.tap { |s2| s2.expressions = [
|
119
|
+
YourDSL::Expression.new(:hi, [], "33"),
|
120
|
+
YourDSL::Expression.new(:hi, [], "34")
|
121
|
+
]}
|
122
|
+
)
|
123
|
+
]}
|
124
|
+
)
|
125
|
+
])
|
126
|
+
assert_equal expected, @@moar_yourdsl
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_conditionally_preserving_procs
|
130
|
+
ast = @@retain_blocks
|
131
|
+
scenario = ast.expressions.first
|
132
|
+
assert_equal :Scenario, scenario.symbol
|
133
|
+
assert_equal "My first awesome scenario", scenario.args
|
134
|
+
given = scenario.scope.expressions.first
|
135
|
+
assert_equal :Given, given.symbol
|
136
|
+
assert_equal "teh shiznit", given.args
|
137
|
+
assert_instance_of Proc, given.proc
|
138
|
+
assert_nil given.scope
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_opt_in_parsing
|
142
|
+
assert_instance_of NoMethodError, @@opt_in_parsing_error
|
143
|
+
assert_match "blech", @@opt_in_parsing_error.message
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_opt_out_parsing
|
147
|
+
begin
|
148
|
+
flunk if @@opt_out_parsing_fail
|
149
|
+
rescue
|
150
|
+
assert_instance_of NoMethodError, @@opt_out_parsing_error
|
151
|
+
assert_match "blech", @@opt_out_parsing_error.message
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/yourdsl.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "yourdsl"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "yourdsl"
|
7
|
+
s.version = YourDSL::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Evan Light", "Ryan Allen"]
|
10
|
+
s.email = ["evan@tripledogdare.net", "ryan@ryanface.com"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/yourdsl"
|
12
|
+
s.summary = %q{~1/2 of a compiler: a partial lexer and nested DSL language implementation}
|
13
|
+
s.description = %q{Records an internal DSL for playback as an AST within Ruby}
|
14
|
+
|
15
|
+
s.rubyforge_project = "yourdsl"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yourdsl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Evan Light
|
9
|
+
- Ryan Allen
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2011-08-08 00:00:00.000000000Z
|
14
|
+
dependencies: []
|
15
|
+
description: Records an internal DSL for playback as an AST within Ruby
|
16
|
+
email:
|
17
|
+
- evan@tripledogdare.net
|
18
|
+
- ryan@ryanface.com
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- .gitignore
|
24
|
+
- Gemfile
|
25
|
+
- MIT-LICENSE
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- example/feature.rb
|
29
|
+
- lib/yourdsl.rb
|
30
|
+
- test/yourdsl_test.rb
|
31
|
+
- yourdsl.gemspec
|
32
|
+
homepage: http://rubygems.org/gems/yourdsl
|
33
|
+
licenses: []
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubyforge_project: yourdsl
|
52
|
+
rubygems_version: 1.8.6
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: ! '~1/2 of a compiler: a partial lexer and nested DSL language implementation'
|
56
|
+
test_files:
|
57
|
+
- test/yourdsl_test.rb
|