Class: DSL::Maker
- Inherits:
-
Object
- Object
- DSL::Maker
- Defined in:
- lib/dsl/maker.rb,
lib/dsl/maker/version.rb
Overview
This is the base class we provide.
Defined Under Namespace
Modules: Boolean Classes: Alias, ArrayType, Base
Constant Summary collapse
- VERSION =
The current version of this library
'0.1.0'- Any =
Create the DSL::Maker::Any type identifier, equivalent to Object.
Object- Yes =
On = True = true
- No =
Off = False = false
- ArrayOf =
Class.new do def self.[](type) raise "Cannot make an array of an alias" if DSL::Maker.is_alias(type) raise "Unknown type provided to ArrayOf" unless @@types.has_key?(type) || DSL::Maker.is_dsl(type) @@arrays[type] ||= ArrayType.new(type) end end
- @@aliases =
{}
- @@arrays =
{}
Class Method Summary collapse
-
.add_entrypoint(name, args = {}, &defn_block) ⇒ Class
Add an entrypoint (top-level DSL element) to this class's DSL.
-
.add_helper(name, &block) ⇒ Object
This adds a helper function that's accessible within the DSL.
-
.add_type(type, &block) ⇒ Object
This adds a type coercion that's used when creating the DSL.
-
.add_verification(name, &block) ⇒ Object
This adds a verification that's executed after the DSL is finished parsing.
- .AliasOf(name) ⇒ Object
-
.entrypoint(name) ⇒ Class
This returns the DSL corresponding to the entrypoint's name.
-
.execute_dsl(&block) ⇒ Object
Execute the DSL provided in the block.
-
.generate_dsl(args = {}, &defn_block) ⇒ Class
Add the meat of a DSL block to some level of this class's DSL.
- .is_alias(type) ⇒ Object
- .is_array(type) ⇒ Object
-
.parse_dsl(dsl = nil) ⇒ Object
Parse the DSL provided in the parameter.
Class Method Details
.add_entrypoint(name, args = {}, &defn_block) ⇒ Class
args could be a Hash (to be passed to generate_dsl()) or the result
Add an entrypoint (top-level DSL element) to this class's DSL.
This delegates to generate_dsl() for the majority of the work.
of a call to generate_dsl().
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/dsl/maker.rb', line 204 def self.add_entrypoint(name, args={}, &defn_block) symname = name.to_sym if is_entrypoint(symname) raise "'#{name.to_s}' is already an entrypoint" end if is_dsl(args) dsl_class = args else # Without defn_block, there's no way to give back the result of the # DSL parsing. So, raise an error if we don't get one. # TODO: Provide a default block that returns the datastructure as a HoH. raise "Block required for add_entrypoint" unless block_given? dsl_class = generate_dsl(args, &defn_block) end if @klass build_dsl_element(@klass, symname, dsl_class) else # FIXME: We shouldn't need the blank block here ... # This blank block is representative of the implicit (and missing) outermost # block around the DSL that we are not putting into place in :parse_dsl or # :execute_dsl. @klass = generate_dsl({ symname => dsl_class }) {} # This marks @klass as the root DSL class. @klass.parent_class = self end @entrypoints ||= {} return @entrypoints[symname] = dsl_class end |
.add_helper(name, &block) ⇒ Object
This adds a helper function that's accessible within the DSL.
Note: These helpers are global to all DSLs.
262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/dsl/maker.rb', line 262 def self.add_helper(name, &block) raise "Block required for add_helper" unless block_given? if DSL::Maker::Base.new.respond_to? name.to_sym raise "'#{name.to_s}' is already a helper" end DSL::Maker::Base.class_eval do define_method(name.to_sym, &block) end return end |
.add_type(type, &block) ⇒ Object
These type coercions are global to all DSLs.
This adds a type coercion that's used when creating the DSL.
Your block will receive the following signature: |attr, *args| where 'attr' is the name of the attribute and *args are the arguments passed into your method within the DSL. You are responsible for acting as a mutator. You have __get() and __set() available for your use. These are aliases to instance_variable_get and instance_variable_set, respectively. Please read the coercions provided for you in this source file as examples.
145 146 147 148 149 150 151 152 |
# File 'lib/dsl/maker.rb', line 145 def self.add_type(type, &block) raise "Block required for add_type" unless block_given? raise "'#{type}' is already a type coercion" if @@types.has_key? type @@types[type] = block return end |
.add_verification(name, &block) ⇒ Object
These verifications are specific to the DSL you add them to.
Verifications are called in the order you specify them.
This adds a verification that's executed after the DSL is finished parsing.
The verification will be called with the value(s) returned by the entrypoint's execution. If the verification returns a true value (of any kind), then that will be raised as a runtime exception.
You can also call add_verification on the return values from generate_dsl() or add_entrypoint(). In those cases, omit the :name because you have already chosen the DSL layer you're adding the verification to.
294 295 296 297 298 299 |
# File 'lib/dsl/maker.rb', line 294 def self.add_verification(name, &block) raise "Block required for add_verification" unless block_given? raise "'#{name.to_s}' is not an entrypoint for a verification" unless is_entrypoint(name) @entrypoints[name.to_sym].add_verification(&block) end |
.AliasOf(name) ⇒ Object
75 76 77 |
# File 'lib/dsl/maker.rb', line 75 def self.AliasOf(name) @@aliases[name] ||= Alias.new(name) end |
.entrypoint(name) ⇒ Class
This returns the DSL corresponding to the entrypoint's name.
246 247 248 249 250 251 252 |
# File 'lib/dsl/maker.rb', line 246 def self.entrypoint(name) unless is_entrypoint(name) raise "'#{name.to_s}' is not an entrypoint" end return @entrypoints[name.to_sym] end |
.execute_dsl(&block) ⇒ Object
If the DSL contains multiple entrypoints, then this will return an
Execute the DSL provided in the block.
Array. This is desirable.
123 124 125 126 127 128 |
# File 'lib/dsl/maker.rb', line 123 def self.execute_dsl(&block) raise 'Must call add_entrypoint before execute_dsl' unless @klass raise 'Block required for execute_dsl' unless block_given? run_dsl { @klass.new.instance_eval(&block) } end |
.generate_dsl(args = {}, &defn_block) ⇒ Class
Add the meat of a DSL block to some level of this class's DSL.
In order for Docile to parse a DSL, each level must be represented by a different class. This method creates anonymous classes that each represents a different level in the DSL's structure.
The creation of each DSL element is delegated to build_dsl_element.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/dsl/maker.rb', line 166 def self.generate_dsl(args={}, &defn_block) raise 'Block required for generate_dsl' unless block_given? dsl_class = Class.new(DSL::Maker::Base) do include DSL::Maker::Boolean class << self attr_accessor :parent_class, :verifications end define_method(:__apply) do |*args| instance_exec(*args, &defn_block) end end args.each do |name, type| if dsl_class.new.respond_to? name.to_sym raise "Illegal attribute name '#{name}'" end build_dsl_element(dsl_class, name, type) end return dsl_class end |
.is_alias(type) ⇒ Object
78 79 80 |
# File 'lib/dsl/maker.rb', line 78 def self.is_alias(type) type.instance_of? Alias end |
.is_array(type) ⇒ Object
96 97 98 |
# File 'lib/dsl/maker.rb', line 96 def self.is_array(type) type.instance_of? ArrayType end |
.parse_dsl(dsl = nil) ⇒ Object
If the DSL contains multiple entrypoints, then this will return an
Parse the DSL provided in the parameter.
Array. This is desirable.
108 109 110 111 112 113 |
# File 'lib/dsl/maker.rb', line 108 def self.parse_dsl(dsl=nil) raise 'Must call add_entrypoint before parse_dsl' unless @klass raise 'String required for parse_dsl' unless dsl.instance_of? String run_dsl { eval dsl, @klass.new.get_binding } end |