dsl_block 1.0.0 → 2.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.
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