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.1'
- 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) ⇒ Array
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.
-
.has_helper?(name) ⇒ Boolean
This returns if the helper has been added with #add_helper.
- .is_alias(type) ⇒ Object
- .is_array(type) ⇒ Object
-
.parse_dsl(dsl = nil) ⇒ Array
Parse the DSL provided in the parameter.
-
.remove_helper(name) ⇒ Object
This removes a helper function that's been added with #add_helper.
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().
198 199 200 201 202 203 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 |
# File 'lib/dsl/maker.rb', line 198 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.
256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/dsl/maker.rb', line 256 def self.add_helper(name, &block) raise "Block required for add_helper" unless block_given? if has_helper? name raise "'#{name.to_s}' is already a helper" end base_class.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.
139 140 141 142 143 144 145 146 |
# File 'lib/dsl/maker.rb', line 139 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.
312 313 314 315 316 317 |
# File 'lib/dsl/maker.rb', line 312 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.
240 241 242 243 244 245 246 |
# File 'lib/dsl/maker.rb', line 240 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) ⇒ Array
Execute the DSL provided in the block.
117 118 119 120 121 122 |
# File 'lib/dsl/maker.rb', line 117 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.
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/dsl/maker.rb', line 160 def self.generate_dsl(args={}, &defn_block) raise 'Block required for generate_dsl' unless block_given? dsl_class = Class.new(base_class) 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 |
.has_helper?(name) ⇒ Boolean
This returns if the helper has been added with #add_helper
290 291 292 |
# File 'lib/dsl/maker.rb', line 290 def self.has_helper?(name) base_class.method_defined?(name.to_sym) 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) ⇒ Array
Parse the DSL provided in the parameter.
105 106 107 108 109 110 |
# File 'lib/dsl/maker.rb', line 105 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 |
.remove_helper(name) ⇒ Object
This removes a helper function that's been added with #add_helper
275 276 277 278 279 280 281 282 283 |
# File 'lib/dsl/maker.rb', line 275 def self.remove_helper(name) unless has_helper? name raise "'#{name.to_s}' is not a helper" end base_class.class_eval do remove_method(name.to_sym) end end |