Class: Qipowl::Bowlers::Bowler

Inherits:
Object
  • Object
show all
Includes:
TypoLogging
Defined in:
lib/qipowl/core/bowler.rb

Overview

Base class for all the parsers.

Technically it may be instantiated, but that’s meaningless. Main operation method for it and all the descendants is #parse. It sequentially executes following private methods:

  • #defreeze
  • #roast
  • #serveup

Normally the developer does not need to interfere the #roast method which proceeds the input string. To prepare the input for +evaluation+ one overwrites #defreeze, for some afterwork the #serveup method is here.

Descendants are supposed to overwrite #method_missing for some custom processing and introduce DSL methods, which will be executed by eval inside the #roast method.

Instance variables :in and :out are here to gain an access to the last interpreted input string and the result of evaluation respectively.

Direct Known Subclasses

Cmd, Html

Constant Summary collapse

SEPARATOR =

Internal constant for joining/splitting the strings during processing. Override on your own risk. I can′t imagine why you would need to do so.

$, || ' '

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TypoLogging

#logger, logger

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

If somebody needs to interfere the standard processing, she supposed to introduce special_handler method. The descendants will be processed before standard operation (which in fact simply collects words within an array one by one.)



66
67
68
69
70
# File 'lib/qipowl/core/bowler.rb', line 66

def method_missing method, *args, &block
  method, *args = special_handler(method, *args, &block) \
    if self.private_methods.include?(:special_handler)
  [method, args].flatten
end

Instance Attribute Details

#inObject (readonly)

Returns the value of attribute in.



36
37
38
# File 'lib/qipowl/core/bowler.rb', line 36

def in
  @in
end

#outObject (readonly)

Returns the value of attribute out.



36
37
38
# File 'lib/qipowl/core/bowler.rb', line 36

def out
  @out
end

Class Method Details

.const_missing(name) ⇒ Object

TODO:

This fails to do with DSLing words, beginning with capitals :-(

Everything is a DSL, remember? Even constants.

Returns:

  • the constant name as is



57
58
59
60
# File 'lib/qipowl/core/bowler.rb', line 57

def self.const_missing name
  raise "There was CONST [#{name}] met. Stupid programming error."
  name
end

Instance Method Details

#add_entity(section, key, value, enclosure_value = null) ⇒ Object

Adds new +entity+ in the section specified. E. g., call to

add_spice :linewide, , :deg, :degrees

in HTML implementation adds a support for specifying something like:

° 15
° 30
° 45

which is to be converted to the following:

<degrees>
  <deg>15</deg>
  <deg>30</deg>
  <deg>45</deg>
</degrees>

Parameters:

  • section (Symbol)

    the section (it must be one of Mapping.SPICES) to add new key to

  • key (Symbol)

    the name for the key

  • value (Symbol)

    the value

  • enclosure_value (Symbol) (defaults to: null)

    optional value to be added for the key into enclosures section



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/qipowl/core/bowler.rb', line 95

def add_entity section, key, value, enclosure_value = null
  if (tags = self.class.const_get("#{section.upcase}_TAGS"))
    key = key.bowl.to_sym
    tags[key] = value.to_sym
    self.class.const_get("ENCLOSURES_TAGS")[key] = enclosure_value.to_sym if enclosure_value
    self.class.class_eval %Q{
      alias_method :#{key}, :∀_#{section}
    } # unless self.class.instance_methods(true).include?(key.bowl)
  else
    logger.warn "Trying to add key “#{key}” in an invalid section “#{section}”. Ignoring…"
  end
end

#block(str) ⇒ Object (private)

Prepares blocks in the input for the execution



206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/qipowl/core/bowler.rb', line 206

def block str
  result = str.dup
  self.class::BLOCK_TAGS.each { |tag, value|
    result.gsub!(/(#{tag})\s*(\S*\s*|$)(.*?)(#{tag}|\Z)/m) {
      %Q{

#{$1}('#{$2.strip}', '#{$3.carriage}')

}
    }
  }
  result
end

#custom(str) ⇒ Object (private)

Prepares customs in the input for the execution



221
222
223
224
225
226
227
# File 'lib/qipowl/core/bowler.rb', line 221

def custom str
  result = str.unbowl.dup
  self.class::CUSTOM_TAGS.each { |tag, value|
    result.gsub!(/#{tag}/, value)
  }
  result.bowl
end

#execute(str) ⇒ Object



42
43
44
# File 'lib/qipowl/core/bowler.rb', line 42

def execute str
  @out = (serveup roast defreeze @in = str)
end

#grip(str) ⇒ Object (private)

Prepares grips in the input for the execution FIX<E There is a problem: we append a trailing space, need to remove it later!!



231
232
233
234
235
236
237
238
239
240
241
# File 'lib/qipowl/core/bowler.rb', line 231

def grip str
  result = str.dup
  self.class::GRIP_TAGS.each { |tag, value|
    result.gsub!(/(?:#{tag})(.*?)(?:#{tag})/m) {
      next if (args = $1).vacant?
      tag = value[:marker] if Hash === value && value[:marker]
      "#{tag} #{args}#{tag}∎⌫"
    }
  }
  result
end

#remove_entity(key) ⇒ Object

Removes key from both Mapping.SPICES and Mapping.SALT. See #add_spice

Parameters:

  • key (Symbol)

    the key to be removed



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/qipowl/core/bowler.rb', line 111

def remove_entity key
  %w(block alone magnet grip regular).each { |section|
    next unless send :"∃_#{section}_tag", key.to_sym
    
    self.class.const_get("#{section.upcase}_TAGS").delete key
    self.class.const_get("ENCLOSURES_TAGS").delete key
    self.class.class_eval %Q{
      remove_method :#{key.bowl}
    }
  }
end

#respond_to?(method) ⇒ Boolean

Everything is a DSL, remember?

Returns:

  • (Boolean)

    true



49
50
51
# File 'lib/qipowl/core/bowler.rb', line 49

def respond_to?(method)
  true
end

#split(str) ⇒ Object (private)



243
244
245
246
247
248
# File 'lib/qipowl/core/bowler.rb', line 243

def split str
  (block str.bowl).split(/\R{2,}/).map { |para|
    para =~ /\A(#{self.class::BLOCK_TAGS.keys.join('|')})\(/ ?
      para : (grip custom para)
  }
end