dsl_block 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6c00534daad8cd4a27d4f3855c4d9a03fad82595
4
- data.tar.gz: 4dfb593b99f4653aecd81b661e4a04533068a87e
3
+ metadata.gz: fc76bcc8987040d930830d224d9c95db5bd212ab
4
+ data.tar.gz: 03de7ce19db4372f7bf411488db80033ff4ae2a4
5
5
  SHA512:
6
- metadata.gz: bb9421a382aca361db5ff31e801d5f064a5789077d68b994aee65a92d87e4385c26631da68466203c5030f6271371db9444a59c9da991e46fcd41f111da462bf
7
- data.tar.gz: 227ebf931eca9fdb584fc51dea8a422a74bfa9fad5823af7127937ef69f0c277efc3c152ebd781f19f4a75cd76c5e0e802d65cfbd5e3783f0215868a965a4376
6
+ metadata.gz: 1abb915845cd07c6384daf018d5bb7fe76515514d85dafd32b2fe7aba723adda356d3b8edca9b5478061c54db0d80cd9196e0879c94d09228f0224f7b8764ecb
7
+ data.tar.gz: acfbb43fe8257490e374801bf0ecf68237e1df6b37f1d4885147bf3dfe0a3ec15effce3f28bbe78264159c86f0fe7ab1b0b530c94088fee510284c8767918df6
data/.gitignore CHANGED
@@ -1,17 +1,17 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
- --colour
2
- --format documentation
1
+ --colour
2
+ --format documentation
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in dsl_block.gemspec
4
- gemspec
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dsl_block.gemspec
4
+ gemspec
@@ -1,22 +1,22 @@
1
- Copyright (c) 2013 Frank Hall
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2013 Frank Hall
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,82 +1,82 @@
1
- # DslBlock
2
-
3
- DslBlock allows you to use classes to define blocks with commands for a Domain Specific Language. The commands are automatically relayed to your instance method.
4
-
5
- ## Installation
6
-
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'dsl_block'
10
-
11
- And then execute:
12
-
13
- $ bundle
14
-
15
- Or install it yourself as:
16
-
17
- $ gem install dsl_block
18
-
19
- ## Usage
20
-
21
- class Foo < DslBlock
22
- commands :show_foo
23
- def show_foo(x)
24
- puts "Mr. T says you are a foo times #{x.to_i}"
25
- end
26
- end
27
-
28
- class Bar < DslBlock
29
- commands :show_bar
30
- def show_bar(x)
31
- puts "Ordering #{x.to_i} Shirley Temples from the bar"
32
- end
33
- end
34
-
35
- class Baz < DslBlock
36
- commands :show_baz
37
- def show_baz(x)
38
- puts "Baz spaz #{x.inspect}"
39
- end
40
- end
41
-
42
- Baz.add_command_to(Bar)
43
- Bar.add_command_to(Foo, true)
44
- Foo.add_command_to(self)
45
-
46
-
47
- foo do
48
- puts self.inspect # => #<Foo:0x007f98f187e240 @block=#<Proc:0x...>, @parent=nil>
49
- x = 10/10
50
- show_foo x # => Mr. T says you are a foo times 1
51
-
52
- bar do
53
- x *= 2
54
- show_bar x # => Ordering 2 Shirley Temples from the bar
55
- x += 1
56
- show_foo x # => Mr. T says you are a foo times 3
57
-
58
- baz do
59
- x *= 4
60
- x /= 3
61
- show_baz x # => Baz spaz 4
62
- begin
63
- x += 1
64
- show_bar 5 # This will throw a NameError
65
- rescue NameError
66
- puts 'No bar for us'
67
- end
68
-
69
- end
70
-
71
- end
72
-
73
- end
74
-
75
-
76
- ## Contributing
77
-
78
- 1. Fork it
79
- 2. Create your feature branch (`git checkout -b my-new-feature`)
80
- 3. Commit your changes (`git commit -am 'Add some feature'`)
81
- 4. Push to the branch (`git push origin my-new-feature`)
82
- 5. Create new Pull Request
1
+ # DslBlock
2
+
3
+ DslBlock allows you to use classes to define blocks with commands for a Domain Specific Language. The commands are automatically relayed to your instance method.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'dsl_block'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install dsl_block
18
+
19
+ ## Usage
20
+
21
+ class Foo < DslBlock
22
+ commands :show_foo
23
+ def show_foo(x)
24
+ puts "Mr. T says you are a foo times #{x.to_i}"
25
+ end
26
+ end
27
+
28
+ class Bar < DslBlock
29
+ commands :show_bar
30
+ def show_bar(x)
31
+ puts "Ordering #{x.to_i} Shirley Temples from the bar"
32
+ end
33
+ end
34
+
35
+ class Baz < DslBlock
36
+ commands :show_baz
37
+ def show_baz(x)
38
+ puts "Baz spaz #{x.inspect}"
39
+ end
40
+ end
41
+
42
+ Baz.add_command_to(Bar)
43
+ Bar.add_command_to(Foo, true)
44
+ Foo.add_command_to(self)
45
+
46
+
47
+ foo do
48
+ puts self.inspect # => #<Foo:0x007f98f187e240 @block=#<Proc:0x...>, @parent=nil>
49
+ x = 10/10
50
+ show_foo x # => Mr. T says you are a foo times 1
51
+
52
+ bar do
53
+ x *= 2
54
+ show_bar x # => Ordering 2 Shirley Temples from the bar
55
+ x += 1
56
+ show_foo x # => Mr. T says you are a foo times 3
57
+
58
+ baz do
59
+ x *= 4
60
+ x /= 3
61
+ show_baz x # => Baz spaz 4
62
+ begin
63
+ x += 1
64
+ show_bar 5 # This will throw a NameError
65
+ rescue NameError
66
+ puts 'No bar for us'
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+
76
+ ## Contributing
77
+
78
+ 1. Fork it
79
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
80
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
81
+ 4. Push to the branch (`git push origin my-new-feature`)
82
+ 5. Create new Pull Request
data/Rakefile CHANGED
@@ -1,16 +1,16 @@
1
- require 'bundler/gem_tasks'
2
- require 'rdoc/task'
3
- require 'rspec/core/rake_task'
4
- require 'rdoc/task'
5
-
6
- RDoc::Task.new do |rdoc|
7
- rdoc.rdoc_dir = 'doc'
8
- rdoc.main = 'DslBlock.html'
9
- rdoc.rdoc_files.include 'lib'
10
- end
11
-
12
-
13
- RSpec::Core::RakeTask.new
14
-
15
- task :default => :spec
1
+ require 'bundler/gem_tasks'
2
+ require 'rdoc/task'
3
+ require 'rspec/core/rake_task'
4
+ require 'rdoc/task'
5
+
6
+ RDoc::Task.new do |rdoc|
7
+ rdoc.rdoc_dir = 'doc'
8
+ rdoc.main = 'DslBlock.html'
9
+ rdoc.rdoc_files.include 'lib'
10
+ end
11
+
12
+
13
+ RSpec::Core::RakeTask.new
14
+
15
+ task :default => :spec
16
16
  task :test => :spec
@@ -1,29 +1,29 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'dsl_block/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = 'dsl_block'
8
- spec.version = DslBlock::VERSION
9
- spec.authors = ['Frank Hall']
10
- spec.email = ['ChapterHouse.Dune@gmail.com']
11
- spec.summary = %q{Quick and simple DSL creator.}
12
- spec.description = %q{DslBlock is a quick and simple DSL creator.}
13
- spec.homepage = 'http://chapterhouse.github.io/dsl_block'
14
- spec.license = 'MIT'
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ['lib']
20
-
21
- spec.add_dependency 'activesupport', '~> 4.0'
22
-
23
- spec.add_development_dependency 'bundler', '~> 1.3'
24
- spec.add_development_dependency 'rake'
25
- spec.add_development_dependency 'rspec', '~> 2.14.1'
26
- spec.add_development_dependency 'simplecov', '~> 0.7.1'
27
- spec.add_development_dependency 'rdoc', '~> 4.0.0'
28
-
29
- end
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dsl_block/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'dsl_block'
8
+ spec.version = DslBlock::VERSION
9
+ spec.authors = ['Frank Hall']
10
+ spec.email = ['ChapterHouse.Dune@gmail.com']
11
+ spec.summary = %q{Quick and simple DSL creator.}
12
+ spec.description = %q{DslBlock is a quick and simple DSL creator.}
13
+ spec.homepage = 'http://chapterhouse.github.io/dsl_block'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'activesupport', '~> 4.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec', '~> 2.14.1'
26
+ spec.add_development_dependency 'simplecov', '~> 0.7.1'
27
+ spec.add_development_dependency 'rdoc', '~> 4.0.0'
28
+
29
+ end
@@ -1,159 +1,168 @@
1
- require 'dsl_block/version'
2
- require 'dsl_block/executor'
3
- require 'active_support/core_ext/string/inflections'
4
-
5
- # DslBlock is a base class for defining a Domain Specific Language. Subclasses of DslBlock define the desired dsl.
6
- # These methods become available to ruby code running in the context of the subclass.
7
- # The block execution is automatically isolated to prevent the called block from accessing instance methods unless
8
- # specifically designated as callable. DslBlocks can be nested and parent blocks can allow their methods to be exposed to child block.
9
- #
10
- # ==== Example
11
- # # Define three DslBlocks each with at least one command in each block
12
- # class Foo < DslBlock
13
- # commands :show_foo
14
- # def show_foo(x)
15
- # "Mr. T says you are a foo times #{x.to_i}"
16
- # end
17
- # end
18
- #
19
- # class Bar < DslBlock
20
- # commands :show_bar
21
- # def show_bar(x)
22
- # "Ordering #{x.to_i} Shirley Temples from the bar"
23
- # end
24
- # end
25
- #
26
- # class Baz < DslBlock
27
- # commands :show_baz
28
- # def show_baz(x)
29
- # "Baz spaz #{x.inspect}"
30
- # end
31
- # end
32
- #
33
- # # Connect the blocks to each other so they can be easily nested
34
- # Baz.add_command_to(Bar)
35
- # Bar.add_command_to(Foo, true) # Let Bar blocks also respond to foo methods
36
- # Foo.add_command_to(self)
37
- #
38
- # # Use the new DSL
39
- # foo do
40
- # self.inspect # => #<Foo:0x007fdbd52b54e0 @block=#<Proc:0x007fdbd52b5530@/home/fhall/wonderland/alice.rb:29>, @parent=nil>
41
- # x = 10/10
42
- # show_foo x # => Mr. T says you are a foo times 1
43
- #
44
- # bar do
45
- # x *= 2
46
- # show_bar x # => Ordering 2 Shirley Temples from the bar
47
- #
48
- # x += 1
49
- # show_foo x # => Mr. T says you are a foo times 3
50
- #
51
- # baz do
52
- #
53
- # x *= 4
54
- # x /= 3
55
- # show_baz x # => Baz spaz 4
56
- #
57
- # begin
58
- # x += 1
59
- # show_bar x # => NameError
60
- # rescue NameError
61
- # 'No bar for us'
62
- # end
63
- # end
64
- #
65
- # end
66
- #
67
- # end
68
- #
69
- class DslBlock
70
- # Parent object providing additional commands to the block.
71
- attr_accessor :parent
72
- # Block of code that will be executed upon yield.
73
- attr_accessor :block
74
-
75
- # With no arguments, returns an array of command names that this DslBlock makes available to blocks either directly or indirectly.
76
- # With arguments, adds new names to the array of command names, then returns the new array.
77
- def self.commands(*args)
78
- @commands ||= []
79
- @commands = (@commands + args.map(&:to_sym)).uniq
80
- @commands
81
- end
82
-
83
- # This is a convenience command that allows this DslBlock to inject itself as a method into another DslBlock or Object.
84
- # If the parent is also a DslBlock, the new method will automatically be added to the available commands.
85
- #
86
- # Params:
87
- # +destination+:: The object to receive the new method
88
- # +propigate_local_commands+:: Allow methods in the destination to be called by the block. (default: false)
89
- # +command_name+:: The name of the method to be created or nil to use the default which is based off of the class name. (default: nil)
90
- def self.add_command_to(destination, propigate_local_commands=false, command_name=nil)
91
- # Determine the name of the method to create
92
- command_name = (command_name || name).to_s.underscore.to_sym
93
- # Save a reference to our self so we will have something to call in a bit when self will refer to someone else.
94
- this_class = self
95
- # Define the command in the destination.
96
- destination.send(:define_method, command_name) do |&block|
97
- # Create a new instance of our self with the callers 'self' passed in as an optional parent.
98
- # Immediately after initialization, yield the block.
99
- this_class.new(propigate_local_commands ? self : nil, &block).yield
100
- end
101
- # Add the new command to the parent if it is a DslBlock.
102
- destination.commands << command_name if destination.is_a?(Class) && destination < DslBlock
103
- end
104
-
105
- # Create a new DslBlock instance.
106
- # +parent+:: Optional parent DslBlock or Object that is providing additional commands to the block. (default: nil)
107
- # +block+:: Required block of code that will be executed when yield is called on the new DslBlock instance.
108
- def initialize(parent = nil, &block)
109
- raise ArgumentError, 'block must be provided' unless block_given?
110
- @block = block
111
- @parent = parent
112
- end
113
-
114
- # This is the entire list of commands that this instance makes available to the block of code to be run.
115
- # It is a combination of three distinct sources.
116
- # 1. The class's declared commands
117
- # 2. If there is a parent of this DslBock instance...
118
- # * The parents declared commands if it is a DslBlock
119
- # * The parents public_methods if it is any other type of object
120
- # 3. Kernel.methods
121
- #
122
- # This method is prefixed with an underscore in an attempt to avoid collisions with commands in the given block.
123
- def _commands
124
- cmds = self.class.commands.dup
125
- if @parent
126
- if @parent.is_a?(DslBlock)
127
- cmds += @parent._commands
128
- else
129
- cmds += @parent.public_methods
130
- end
131
- end
132
- (cmds + Kernel.methods).uniq
133
- end
134
-
135
- # Yield the block given.
136
- def yield
137
- begin
138
- # Evaluate the block in an executor to provide isolation
139
- # and prevent accidental interference with ourselves.
140
- Executor.new(self).instance_eval(&@block)
141
- rescue Exception => e
142
- e.set_backtrace(caller.select { |x| !x.include?(__FILE__)})
143
- raise e
144
- end
145
- end
146
-
147
- # :nodoc:
148
- def respond_to_missing?(method, include_all)
149
- @parent && @parent.respond_to?(method, include_all) || super
150
- end
151
-
152
- def method_missing(name, *args, &block)
153
- if @parent && @parent.respond_to?(name)
154
- @parent.send(name, *args, &block)
155
- else
156
- super
157
- end
158
- end
159
- end
1
+ require 'dsl_block/version'
2
+ require 'dsl_block/executor'
3
+ require 'active_support/core_ext/string/inflections'
4
+ require 'active_support/core_ext/array/extract_options'
5
+
6
+
7
+ # DslBlock is a base class for defining a Domain Specific Language. Subclasses of DslBlock define the desired dsl.
8
+ # These methods become available to ruby code running in the context of the subclass.
9
+ # The block execution is automatically isolated to prevent the called block from accessing instance methods unless
10
+ # specifically designated as callable. DslBlocks can be nested and parent blocks can allow their methods to be exposed to child block.
11
+ #
12
+ # ==== Example
13
+ # # Define three DslBlocks each with at least one command in each block
14
+ # class Foo < DslBlock
15
+ # commands :show_foo
16
+ # def show_foo(x)
17
+ # "Mr. T says you are a foo times #{x.to_i}"
18
+ # end
19
+ # end
20
+ #
21
+ # class Bar < DslBlock
22
+ # commands :show_bar
23
+ # def show_bar(x)
24
+ # "Ordering #{x.to_i} Shirley Temples from the bar"
25
+ # end
26
+ # end
27
+ #
28
+ # class Baz < DslBlock
29
+ # commands :show_baz
30
+ # def show_baz(x)
31
+ # "Baz spaz #{x.inspect}"
32
+ # end
33
+ # end
34
+ #
35
+ # # Connect the blocks to each other so they can be easily nested
36
+ # Baz.add_command_to(Bar)
37
+ # Bar.add_command_to(Foo, :propagate => true) # Let Bar blocks also respond to foo methods
38
+ # Foo.add_command_to(self)
39
+ #
40
+ # # Use the new DSL
41
+ # foo do
42
+ # self.inspect # => #<Foo:0x007fdbd52b54e0 @block=#<Proc:0x007fdbd52b5530@/home/fhall/wonderland/alice.rb:29>, @parent=nil>
43
+ # x = 10/10
44
+ # show_foo x # => Mr. T says you are a foo times 1
45
+ #
46
+ # bar do
47
+ # x *= 2
48
+ # show_bar x # => Ordering 2 Shirley Temples from the bar
49
+ #
50
+ # x += 1
51
+ # show_foo x # => Mr. T says you are a foo times 3
52
+ #
53
+ # baz do
54
+ #
55
+ # x *= 4
56
+ # x /= 3
57
+ # show_baz x # => Baz spaz 4
58
+ #
59
+ # begin
60
+ # x += 1
61
+ # show_bar x # => NameError
62
+ # rescue NameError
63
+ # 'No bar for us'
64
+ # end
65
+ # end
66
+ #
67
+ # end
68
+ #
69
+ # end
70
+ #
71
+ class DslBlock
72
+ # Parent object providing additional commands to the block.
73
+ attr_accessor :parent
74
+ # Block of code that will be executed upon yield.
75
+ attr_accessor :block
76
+
77
+ # With no arguments, returns an array of command names that this DslBlock makes available to blocks either directly or indirectly.
78
+ # With arguments, adds new names to the array of command names, then returns the new array.
79
+ def self.commands(*args)
80
+ @commands ||= []
81
+ @commands = (@commands + args.map(&:to_sym)).uniq
82
+ @commands
83
+ end
84
+
85
+ # This is a convenience command that allows this DslBlock to inject itself as a method into another DslBlock or Object.
86
+ # If the parent is also a DslBlock, the new method will automatically be added to the available commands.
87
+ #
88
+ # Params:
89
+ # +destination+:: The object to receive the new method
90
+ # +options+:: A hash of options configuring the command
91
+ #
92
+ # Options:
93
+ # +:propagate+:: Allow methods in the destination to be called by the block. (default: false)
94
+ # +:command_name+:: The name of the method to be created or nil to use the default which is based off of the class name. (default: nil)
95
+ def self.add_command_to(destination, options={})
96
+ # Determine the name of the method to create
97
+ command_name = (options[:command_name] || name).to_s.underscore.to_sym
98
+ # Save a reference to our self so we will have something to call in a bit when self will refer to someone else.
99
+ this_class = self
100
+ # Define the command in the destination.
101
+ destination.send(:define_method, command_name) do |&block|
102
+ # Create a new instance of our self with the callers 'self' passed in as an optional parent.
103
+ # Immediately after initialization, yield the block.
104
+ this_class.new(:parent => options[:propagate] ? self : nil, &block).yield
105
+ end
106
+ # Add the new command to the parent if it is a DslBlock.
107
+ destination.commands << command_name if destination.is_a?(Class) && destination < DslBlock
108
+ end
109
+
110
+ # Create a new DslBlock instance.
111
+ # +block+:: Required block of code that will be executed when yield is called on the new DslBlock instance.
112
+ #
113
+ # Options:
114
+ # +:parent+:: Optional parent DslBlock or Object that is providing additional commands to the block. (default: nil)
115
+ # +:block+:: Optional method of passing in a block.
116
+ def initialize(*args, &block)
117
+ options = args.extract_options!
118
+ @block = block_given? ? block : options[:block]
119
+ raise ArgumentError, 'block must be provided' unless @block
120
+ @parent = options[:parent]
121
+ end
122
+
123
+ # This is the entire list of commands that this instance makes available to the block of code to be run.
124
+ # It is a combination of three distinct sources.
125
+ # 1. The class's declared commands
126
+ # 2. If there is a parent of this DslBock instance...
127
+ # * The parents declared commands if it is a DslBlock
128
+ # * The parents public_methods if it is any other type of object
129
+ # 3. Kernel.methods
130
+ #
131
+ # This method is prefixed with an underscore in an attempt to avoid collisions with commands in the given block.
132
+ def _commands
133
+ cmds = self.class.commands.dup
134
+ if @parent
135
+ if @parent.is_a?(DslBlock)
136
+ cmds += @parent._commands
137
+ else
138
+ cmds += @parent.public_methods
139
+ end
140
+ end
141
+ (cmds + Kernel.methods).uniq
142
+ end
143
+
144
+ # Yield the block given.
145
+ def yield
146
+ begin
147
+ # Evaluate the block in an executor to provide isolation
148
+ # and prevent accidental interference with ourselves.
149
+ Executor.new(self).instance_eval(&@block)
150
+ rescue Exception => e
151
+ e.set_backtrace(caller.select { |x| !x.include?(__FILE__)})
152
+ raise e
153
+ end
154
+ end
155
+
156
+ # :nodoc:
157
+ def respond_to_missing?(method, include_all)
158
+ @parent && @parent.respond_to?(method, include_all) || super
159
+ end
160
+
161
+ def method_missing(name, *args, &block)
162
+ if @parent && @parent.respond_to?(name)
163
+ @parent.send(name, *args, &block)
164
+ else
165
+ super
166
+ end
167
+ end
168
+ end