iron-dsl 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 58e6a28f277a7fb6305e7ffb268f26d2f737c0e2
4
+ data.tar.gz: 2e08931bde299f5ac6f84f93f924b3e4beecf85f
5
+ SHA512:
6
+ metadata.gz: 51b0a8cea42976e123c25471d8558cdea7e4f53ecd8d47de187d9551f87ec4f55429087fd9826f893ce18e729cfb3baffe344b6f942772f2d8fe28b8a0748bb4
7
+ data.tar.gz: 55e093337f7a637640d4d99acb6b4880be3515aabc0f949c23fb8ceaf5ea7a043dbdb62bc4a46145d1e8b4691a3c7e71fd02507da0ce5aea39384abb1c2ba352
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require <%= File.join(File.expand_path(File.dirname(__FILE__)), 'spec', 'spec_helper.rb') %>
@@ -0,0 +1,5 @@
1
+ == 1.0.0 / 2015-01-26
2
+
3
+ * Broke out iron-dsl from older iron-extensions gem
4
+ * Improved documentation a bit
5
+ * Updated dsl_accessor to capture blocks
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Irongaze Consulting LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,149 @@
1
+ = GEM: iron-dsl
2
+
3
+ Written by Rob Morris @ Irongaze Consulting LLC (http://irongaze.com)
4
+
5
+ == DESCRIPTION
6
+
7
+ The iron-dsl gem provides a set of powerful tools for building "domain-specific languages"
8
+ in Ruby. Ruby's natural DSL construction capabilities (through, e.g. instance_eval) are
9
+ very solid, but to make truly clean DSLs requires additional magic. This gem provides
10
+ that magic in a nice self-contained package.
11
+
12
+ == USAGE
13
+
14
+ There are 3 main pieces to this gem: DslBuilder, a set of accessor helpers, and DslProxy.
15
+
16
+ DslBuilder is simply an empty class, suitable for use as a base class for your DSL receiver class.
17
+ It is similar to BasicObject in the standard library, but has methods such as #respond_to?
18
+ and #send that are required for any real DSL building effort.
19
+
20
+ You can use DslBuilder, or any other class, as the basis for your DSL system. In any case,
21
+ you want a clean way to set attributes on an instance of that class. For that, we have
22
+ two class-level methods: #dsl_accessor and #dsl_flag
23
+
24
+ The first, #dsl_accessor, is a helpful method for defining accessors on DSL builder-style classes:
25
+
26
+ require 'iron/dsl'
27
+
28
+ class MyBuilder < DslBuilder
29
+ # Declare an accessor on this receiver class, just like you'd use attr_accessor
30
+ dsl_accessor :name
31
+ end
32
+
33
+ # When you create an instance, you have a set of behavior for the #name accessor you declared
34
+ builder = MyBuilder.new
35
+
36
+ # You can set a value by calling #name as a setter, and get the value by using #name as a getter
37
+ builder.name = 'ProjectX'
38
+ builder.name # => 'ProjectX'
39
+
40
+ # But you can also set the value by simply calling #name with the value to set:
41
+ builder.name 'ProjectY'
42
+ builder.name # => 'ProjectY'
43
+
44
+ # This makes for a cleaner syntax when using your DSL with DslProxy#exec below..
45
+ DslProxy.exec(builder) do
46
+ name 'Project Omega'
47
+ end
48
+ builder.name # => 'Project Omega'
49
+
50
+ # You can also capture blocks this way, which is often useful in DSL creation for values
51
+ # that need to be dynamically calculated at run-time
52
+ builder.name do
53
+ "Project " + Date.today
54
+ end
55
+
56
+ The second accessor helper is #dsl_flag, which is the same as #dsl_accessor, but designed for
57
+ boolean values.
58
+
59
+ class AnotherBuilder < DslBuilder
60
+ dsl_flag :awesome
61
+ end
62
+
63
+ builder = AnotherBuilder
64
+ builder.awesome? # => false on uninitialized value
65
+ builder.awesome! # => sets @awesome to true
66
+ # dsl_flags can still be set normally
67
+ builder.awesome true
68
+ builder.awesome false
69
+
70
+ Bringing it all together, and the key to the whole system, is DslProxy. DslProxy is a more powerful version of
71
+ #instance_exec that handles instance variable propagation and other nifty tricks like nesting and propagating
72
+ method references and constant lookups to the calling scope. That all sounds like gibberish, so here's a few
73
+ hopefully illustrative examples.
74
+
75
+ @name = 'Bob'
76
+
77
+ # First, how you would traditionally do it:
78
+ instance_exec(some_receiver) do
79
+ # This fails - the instance var from the calling context is not defined. Sucks if you're in Rails
80
+ # and trying to define something in a controller or view, where all the state is typically in
81
+ # instance vars!
82
+ self.name = @name
83
+ end
84
+
85
+ # This, however, totally works
86
+ DslProxy.exec(some_receiver) do
87
+ # @name has bubbled into our block and can be referenced!
88
+ self.name = @name
89
+ # But of course, we'd use a dsl_accessor so we could lose the 'self.' and the '='
90
+ name @name
91
+
92
+ # Having nested DSLs is also supported, all instance vars are available at all levels
93
+ sub_define do
94
+ page_title @name + ' Likes Bees'
95
+ end
96
+ end
97
+
98
+ In summary, making DSLs is a bit of an art, and what this gem attempts to do is make pretty DSLs like this
99
+ easier to build:
100
+
101
+ grid = Grid.define do
102
+ url '/orders/grid'
103
+ souce Order.by_date
104
+
105
+ columns do
106
+ column :id
107
+ column :customer do
108
+ no_wrap!
109
+ column :total do
110
+ render_as :currency
111
+ end
112
+ end
113
+
114
+ pagination do
115
+ default 40
116
+ allow_custom!
117
+ end
118
+ end
119
+
120
+ Using code to configure complex systems (rather than hashes of hashes, or manually constructed settings objects)
121
+ allows for a much more expressive codebase. At Irongaze, we use this type of builder for grid controls, pagination,
122
+ filters, forms, fields, and so forth. Places where the MVC system breaks down, and complexity that bridges
123
+ controller and view needs to be managed.
124
+
125
+ == SYNOPSIS
126
+
127
+ To use:
128
+
129
+ require 'iron/dsl'
130
+
131
+ After that, simply write code to make use of the new extensions and helper classes.
132
+
133
+ == REQUIREMENTS
134
+
135
+ * Ruby 1.9.2 or later
136
+
137
+ == INSTALL
138
+
139
+ To install, simply run:
140
+
141
+ sudo gem install iron-dsl
142
+
143
+ RVM users should drop the 'sudo':
144
+
145
+ gem install iron-dsl
146
+
147
+ Then simply require the library:
148
+
149
+ require 'iron/dsl'
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,5 @@
1
+ # Requires all classes
2
+ search_path = File.join(File.expand_path(File.dirname(__FILE__)), '*', '*.rb')
3
+ Dir.glob(search_path) do |path|
4
+ require path
5
+ end
@@ -0,0 +1,46 @@
1
+ class Class
2
+
3
+ # Provides a DSL-friendly way to set values. Similar to attr_accessor, but
4
+ # supports setting values like so:
5
+ #
6
+ # class Widget
7
+ # dsl_accessor :size
8
+ # end
9
+ # @w = Widget.new
10
+ # @w.size = 5 # normal setter, same as...
11
+ # @w.size 5 # note the lack of explicit = sign
12
+ # puts @w.size # still get reader access
13
+ #
14
+ # Useful in DslProxy blocks:
15
+ #
16
+ # DslProxy.exec(Widget.new) do
17
+ # size 10 # sets size to 10, as expected
18
+ # size = 10 # fails, creates local variable 'size' instead of invoking Widget#size
19
+ # end
20
+ #
21
+ def dsl_accessor(*keys)
22
+ keys.each do |key|
23
+ class_eval "def #{key}(val = :__UNDEFINED, &block); if val != :__UNDEFINED ; @#{key} = val ; elsif block ; @#{key} = block ; end ; @#{key}; end"
24
+ class_eval "def #{key}=(val); @#{key} = val; end"
25
+ end
26
+ end
27
+
28
+ # Like #dsl_accessor, but adds imperative and query versions of the keys as well to set the
29
+ # flag to true and to query the true-ness of the flag.
30
+ #
31
+ # class Widget
32
+ # dsl_flag :heavy
33
+ # end
34
+ # @w = Widget.new
35
+ # @w.heavy? # => false
36
+ # @w.heavy! # now is true
37
+ #
38
+ def dsl_flag(*keys)
39
+ dsl_accessor(*keys)
40
+ keys.each do |key|
41
+ class_eval "def #{key}!; @#{key} = true; end"
42
+ class_eval "def #{key}?; @#{key} === true; end"
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,14 @@
1
+ # Provides a base class for building DSL (domain specific language) builder
2
+ # classes, ie classes that define a minimal subset of methods and act as aggregators
3
+ # of settings or functionality. Similar to BasicObject in the standard library, but
4
+ # has methods such as respond_to? and send that are required for any real DSL building
5
+ # effort.
6
+ class DslBuilder < Object
7
+
8
+ # Remove all methods not explicitly desired
9
+ instance_methods.each do |m|
10
+ keepers = [:inspect, :send]
11
+ undef_method m if m =~ /^[a-z]+[0-9]?$/ && !keepers.include?(m)
12
+ end
13
+
14
+ end
@@ -0,0 +1,176 @@
1
+ # Specialty helper class for building elegant DSLs (domain-specific languages)
2
+ # The purpose of the class is to allow seamless DSL's by allowing execution
3
+ # of blocks with the instance variables of the calling context preserved, but
4
+ # all method calls proxied to a given receiver. This sounds pretty abstract,
5
+ # so here's an example:
6
+ #
7
+ # class ControlBuilder
8
+ # def initialize; @controls = []; end
9
+ # def control_list; @controls; end
10
+ # def knob; @controls << :knob; end
11
+ # def button; @controls << :button; end
12
+ # def switch; @controls << :switch; end
13
+ # def self.define(&block)
14
+ # @builder = self.new
15
+ # DslProxy.exec(@builder, &block)
16
+ # # Do something here with the builder's list of controls
17
+ # @builder.control_list
18
+ # end
19
+ # end
20
+ #
21
+ # @knob_count = 5
22
+ # new_list = ControlBuilder.define do
23
+ # switch
24
+ # @knob_count.times { knob }
25
+ # button
26
+ # end
27
+ #
28
+ # Notice the lack of explicit builder receiver to the calls to #switch, #knob and #button.
29
+ # Those calls are automatically proxied to the receiver we passed to the DslProxy.
30
+ #
31
+ # In quick and dirty DSLs, like Rails' migrations, you end up with a lot of
32
+ # pointless receiver declarations for each method call, like so:
33
+ #
34
+ # def change
35
+ # create_table do |t|
36
+ # t.integer :counter
37
+ # t.text :title
38
+ # t.text :desc
39
+ # # ... tired of typing "t." yet? ...
40
+ # end
41
+ # end
42
+ #
43
+ # This is not a big deal if you're using a simple DSL, but when you have multiple nested
44
+ # builders going on at once, it is ugly, pointless, and can cause bugs when
45
+ # the throwaway arg names you choose (eg 't' above) overlap in scope.
46
+ #
47
+ # In addition, simply using a yield statment loses the instance variables set in the calling
48
+ # context. This is a major pain in eg Rails views, where most of the interesting
49
+ # data resides in instance variables. You can get around this when #yield-ing by
50
+ # explicitly creating a local variable to be picked up by the closure created in the
51
+ # block, but it kind of sucks.
52
+ #
53
+ # In summary, DslProxy allows you to keep all the local and instance variable context
54
+ # from your block declarations, while proxying all method calls to a given
55
+ # receiver. If you're not building DSLs, this class is not for you, but if you are,
56
+ # I hope it helps!
57
+ class DslProxy < BasicObject
58
+
59
+ # Pass in a builder-style class, or other receiver you want set as "self" within the
60
+ # block, and off you go. The passed block will be executed with all
61
+ # block-context local and instance variables available, but with all
62
+ # method calls sent to the receiver you pass in. The block's result will
63
+ # be returned.
64
+ #
65
+ # If the receiver doesn't respond_to? a method, any missing methods
66
+ # will be proxied to the enclosing context.
67
+ def self.exec(receiver, *to_yield, &block) # :yields: receiver
68
+ # Find the context within which the block was defined
69
+ context = ::Kernel.eval('self', block.binding)
70
+
71
+ # Create or re-use our proxy object
72
+ if context.respond_to?(:_to_dsl_proxy)
73
+ # If we're nested, we don't want/need a new dsl proxy, just re-use the existing one
74
+ proxy = context._to_dsl_proxy
75
+ else
76
+ # Not nested, create a new proxy for our use
77
+ proxy = DslProxy.new(context)
78
+ end
79
+
80
+ # Exec the block and return the result
81
+ proxy._proxy(receiver, *to_yield, &block)
82
+ end
83
+
84
+ # Simple state setup
85
+ def initialize(context)
86
+ @_receivers = []
87
+ @_instance_original_values = {}
88
+ @_context = context
89
+ end
90
+
91
+ def _proxy(receiver, *to_yield, &block) # :yields: receiver
92
+ # Sanity!
93
+ raise 'Cannot proxy with a DslProxy as receiver!' if receiver.respond_to?(:_to_dsl_proxy)
94
+
95
+ if @_receivers.empty?
96
+ # On first proxy call, run each context instance variable,
97
+ # and set it to ourselves so we can proxy it
98
+ @_context.instance_variables.each do |var|
99
+ unless var[0...2] == '@_'
100
+ value = @_context.instance_variable_get(var.to_s)
101
+ @_instance_original_values[var] = value
102
+ instance_eval "#{var} = value"
103
+ end
104
+ end
105
+ end
106
+
107
+ # Save the dsl target as our receiver for proxying
108
+ _push_receiver(receiver)
109
+
110
+ # Run the block with ourselves as the new "self", passing the given yieldable(s) or
111
+ # the receiver in case the code wants to disambiguate for some reason
112
+ to_yield = [receiver] if to_yield.empty?
113
+ to_yield = to_yield.first(block.arity)
114
+ result = instance_exec(*to_yield, &block)
115
+
116
+ # Pop the last receiver off the stack
117
+ _pop_receiver
118
+
119
+ if @_receivers.empty?
120
+ # Run each local instance variable and re-set it back to the context if it has changed during execution
121
+ #instance_variables.each do |var|
122
+ @_context.instance_variables.each do |var|
123
+ unless var[0...2] == '@_'
124
+ value = instance_eval("#{var}")
125
+ if @_instance_original_values[var] != value
126
+ @_context.instance_variable_set(var.to_s, value)
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ return result
133
+ end
134
+
135
+ # For nesting multiple proxies
136
+ def _to_dsl_proxy
137
+ self
138
+ end
139
+
140
+ # Set the currently active receiver
141
+ def _push_receiver(receiver)
142
+ @_receivers.push receiver
143
+ end
144
+
145
+ # Remove the currently active receiver, restore old receiver if nested
146
+ def _pop_receiver
147
+ @_receivers.pop
148
+ end
149
+
150
+ # Proxies all calls to our receiver, or to the block's context
151
+ # if the receiver doesn't respond_to? it.
152
+ def method_missing(method, *args, &block)
153
+ #$stderr.puts "Method missing: #{method}"
154
+ if @_receivers.last.respond_to?(method)
155
+ #$stderr.puts "Proxy [#{method}] to receiver"
156
+ @_receivers.last.__send__(method, *args, &block)
157
+ else
158
+ #$stderr.puts "Proxy [#{method}] to context"
159
+ @_context.__send__(method, *args, &block)
160
+ end
161
+ end
162
+
163
+ # Let anyone who's interested know what our proxied objects will accept
164
+ def respond_to?(method, include_private = false)
165
+ return true if method == :_to_dsl_proxy
166
+ @_receivers.last.respond_to?(method, include_private) || @_context.respond_to?(method, include_private)
167
+ end
168
+
169
+ # Proxies searching for constants to the context, so that eg Kernel::foo can actually
170
+ # find Kernel - BasicObject does not partake in the global scope!
171
+ def self.const_missing(name)
172
+ #$stderr.puts "Constant missing: #{name} - proxy to context"
173
+ @_context.class.const_get(name)
174
+ end
175
+
176
+ end
@@ -0,0 +1,33 @@
1
+ describe Class do
2
+
3
+ context 'when using dsl_accessor' do
4
+ class MyBuilder < DslBuilder
5
+ dsl_accessor :process
6
+ end
7
+
8
+ before do
9
+ @builder = MyBuilder.new
10
+ end
11
+
12
+ it 'should set via =' do
13
+ @builder.process.should be_nil
14
+ @builder.process = 5
15
+ @builder.process.should == 5
16
+ end
17
+
18
+ it 'should set via call' do
19
+ @builder.process.should be_nil
20
+ @builder.process 5
21
+ @builder.process.should == 5
22
+ end
23
+
24
+ it 'should capture blocks' do
25
+ @builder.process do
26
+ puts 'foo'
27
+ end
28
+ @builder.process.should be_a Proc
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,29 @@
1
+ describe DslBuilder do
2
+
3
+ # TODO: break this out a bit...
4
+ it 'should allow using DSL-style accessors' do
5
+ class MyBuilder < DslBuilder
6
+ dsl_accessor :name
7
+ dsl_flag :flagged
8
+ end
9
+ builder = MyBuilder.new
10
+
11
+ # Test standalone
12
+ builder.name 'ProjectX'
13
+ builder.name.should == 'ProjectX'
14
+
15
+ builder.flagged?.should be_false
16
+ builder.flagged = true
17
+ builder.flagged?.should be_true
18
+ builder.flagged = false
19
+
20
+ # Test as part of DslProxy usage (common case)
21
+ DslProxy.exec(builder) do
22
+ name 'Project Omega'
23
+ flagged!
24
+ end
25
+ builder.name.should == 'Project Omega'
26
+ builder.flagged?.should be_true
27
+ end
28
+
29
+ end
@@ -0,0 +1,110 @@
1
+ describe DslProxy do
2
+
3
+ # Sample DSL builder class for use in testing
4
+ class ControlBuilder
5
+ def initialize; @controls = []; end
6
+ def controls; @controls; end
7
+ def knob; @controls << :knob; end
8
+ def button; @controls << :button; end
9
+ def switch; @controls << :switch; end
10
+
11
+ def self.define(&block)
12
+ @builder = self.new
13
+ DslProxy.exec(@builder, &block)
14
+ @builder.controls
15
+ end
16
+ end
17
+
18
+ it 'should proxy calls to the receiver' do
19
+ receiver = Object.new
20
+ DslProxy.exec(receiver) do
21
+ self.class.name.should == 'Object'
22
+ end
23
+ end
24
+
25
+ it 'should proxy respond_to? to the receiver' do
26
+ receiver = ControlBuilder.new
27
+ DslProxy.exec(receiver) do
28
+ respond_to?(:garbaz).should == false
29
+ respond_to?(:button).should == true
30
+ end
31
+ end
32
+
33
+ it 'should proxy local variables from the binding context' do
34
+ @foo = 'bar'
35
+ DslProxy.exec(Object.new) do
36
+ @foo.should == 'bar'
37
+ end
38
+ end
39
+
40
+ it 'should propagate local variable changes back to the binding context' do
41
+ @foo = 'bar'
42
+ DslProxy.exec(Object.new) do
43
+ @foo = 'no bar!'
44
+ end
45
+ @foo.should == 'no bar!'
46
+ end
47
+
48
+ it 'should proxy missing methods on the receiver to the calling context' do
49
+ class TestContext
50
+ def bar
51
+ 'something'
52
+ end
53
+
54
+ def test
55
+ DslProxy.exec(Object.new) do
56
+ bar
57
+ end
58
+ end
59
+ end
60
+
61
+ TestContext.new.test.should == 'something'
62
+ end
63
+
64
+ it 'should return the result of the block' do
65
+ res = DslProxy.exec(Object.new) do
66
+ 'foo'
67
+ end
68
+ res.should == 'foo'
69
+ end
70
+
71
+ it 'should allow access to global constants' do
72
+ DslProxy.exec(self) do # Use self here, so #be_a is defined. :-)
73
+ Object.new.should be_a(Object)
74
+ end
75
+ end
76
+
77
+ it 'should proxy correctly even when nested' do
78
+ def outerfunc
79
+ 5
80
+ end
81
+ @instance_var = nil
82
+ local_var = nil
83
+ DslProxy.exec(self) do
84
+ DslProxy.exec(Object.new) do
85
+ outerfunc.should == 5
86
+ @instance_var.should be_nil
87
+ local_var.should be_nil
88
+ @instance_var = 10
89
+ local_var = 11
90
+ end
91
+ end
92
+ @instance_var.should == 10
93
+ local_var.should == 11
94
+ end
95
+
96
+ it 'should pass additional args to block as argument' do
97
+ l = lambda {|arg1, arg2| arg1 + arg2}
98
+ DslProxy.exec(Object.new, 5, 1, &l).should == 6
99
+ end
100
+
101
+ it 'should put it all together' do
102
+ @knob_count = 5
103
+ controls = ControlBuilder.define do
104
+ switch
105
+ @knob_count.times { knob }
106
+ end
107
+ controls.count.should == 6
108
+ end
109
+
110
+ end
@@ -0,0 +1,11 @@
1
+ # Require our library
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'iron', 'dsl'))
3
+
4
+ # Config RSpec options
5
+ RSpec.configure do |config|
6
+ config.color = true
7
+ config.add_formatter 'documentation'
8
+ config.backtrace_clean_patterns = [/rspec/]
9
+ end
10
+
11
+
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: iron-dsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rob Morris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
27
+ description: Provides the DslProxy and DslBuilder classes plus DSL-friendly accessor
28
+ and flag support
29
+ email:
30
+ - rob@irongaze.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".rspec"
36
+ - History.txt
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Version.txt
40
+ - lib/iron/dsl.rb
41
+ - lib/iron/dsl/class.rb
42
+ - lib/iron/dsl/dsl_builder.rb
43
+ - lib/iron/dsl/dsl_proxy.rb
44
+ - spec/dsl/class_spec.rb
45
+ - spec/dsl/dsl_builder_spec.rb
46
+ - spec/dsl/dsl_proxy_spec.rb
47
+ - spec/spec_helper.rb
48
+ homepage: https://github.com/irongaze/iron-dsl
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.9.2
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.4.3
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Powerful and concise construction helpers for Domain Specific Languages
72
+ test_files: []