Class: HamlToStar::Compiler

Inherits:
Object
  • Object
show all
Defined in:
lib/haml_to_star/compiler.rb

Overview

The compiler class transform an haml code to executable code.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCompiler

Returns a new instance of Compiler.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/haml_to_star/compiler.rb', line 35

def initialize
  @variable_name = '_$output'
  @variable_line_name = '_$line'
  @self_closing = [
  'meta',
  'img',
  'link',
  'br',
  'hr',
  'input',
  'area',
  'base']
  
  @doc_types = {
    '5' => '<!DOCTYPE html>',
    'xml' => '<?xml version="1.0" encoding="utf-8" ?>',
    'default' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
    'strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
    'frameset' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
    '1.1' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
    'basic' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
    'mobile' => '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
  }
end

Instance Attribute Details

#doc_types{String => String}

Shortcuts for doc types (ex: ‘xml’ => ‘<?xml version=“1.0” encoding=“utf-8” ?>’)

Returns:

  • ({String => String})


28
29
30
# File 'lib/haml_to_star/compiler.rb', line 28

def doc_types
  @doc_types
end

#line_numberInteger

Current line number

Returns:

  • (Integer)


33
34
35
# File 'lib/haml_to_star/compiler.rb', line 33

def line_number
  @line_number
end

#self_closingArray<String>

Self closing html tags (like meta or img)

Returns:

  • (Array<String>)


23
24
25
# File 'lib/haml_to_star/compiler.rb', line 23

def self_closing
  @self_closing
end

#variable_line_nameString

Variable name in which we save current haml line code (debugging)

Returns:

  • (String)


18
19
20
# File 'lib/haml_to_star/compiler.rb', line 18

def variable_line_name
  @variable_line_name
end

#variable_nameString

Variable name in which we save resulting html.

Returns:

  • (String)


13
14
15
# File 'lib/haml_to_star/compiler.rb', line 13

def variable_name
  @variable_name
end

Instance Method Details

#add_code(str, line, inside) ⇒ Object

How do we add code content to the result

Parameters:

  • str (String)

    Result string

  • line (String)

    Current line

  • inside (String)

    Children lines



333
334
335
# File 'lib/haml_to_star/compiler.rb', line 333

def add_code(str, line, inside)
  raise 'To be defined'
end

#add_content(str, content) ⇒ Object

How do we add html content to the result

Parameters:

  • str (String)

    Result string

  • content (String)

    Generated code



324
325
326
# File 'lib/haml_to_star/compiler.rb', line 324

def add_content(str, content)
  raise 'To be defined'
end

#construct_dom(params) ⇒ String

Converts object sent by convert_dom_element into a valid dom element.

Parameters:

  • params (Object)

    Params sent by convert_dom_element

Returns:

  • (String)


271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/haml_to_star/compiler.rb', line 271

def construct_dom(params)
  dom = {}
  dom[:self_closing] = @self_closing.index(params[:tag])
  dom[:begin] = '\'<' + params[:tag] + ' '
  if (params[:dom_params])
    extend = {}
    if (params[:id])
      extend[:id] = params[:id]
    end
    if (params[:class])
      extend[:class] = params[:class]
    end
    dom[:begin] += '\' + attrs(' + params[:dom_params] + ', ' + extend.to_json + ') + \''
  else
    if (params[:id])
      dom[:begin] += 'id="' + params[:id] + '" '
    end
    if (params[:class])
      dom[:begin] += 'class="' + params[:class] + '" '
    end
  end
  dom[:begin] += (dom[:self_closing] ? '/' : '') + '>\''
  if (params[:inside])
    dom[:inside] = CGI::escapeHTML(params[:inside])
  elsif (params[:inside_code])
    dom[:inside] = params[:inside_code]
  end
  
  dom[:end] = '\'</' + params[:tag] + '>\''
  return dom
end

#convert_dom_element(line) ⇒ String

Converts a line in the haml code into a valid dom element.

Parameters:

  • line (String)

    The haml code line

Returns:

  • (String)


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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/haml_to_star/compiler.rb', line 215

def convert_dom_element(line)
  div_base_informations = line.gsub(%r{[^\{ =]*}).first
  infos = div_base_informations.gsub(%r{[%.#][\w-]*})
  params = {:tag => 'div'}
  infos.each do |info|
    if (info[0] == '%')
      params[:tag] = info[1..info.size - 1]
    elsif (info[0] == '#')
      params[:id] = info[1..info.size - 1]
    elsif (info[0] == '.')
      unless params[:class]
        params[:class] = ''
      end
      params[:class] += ' ' + info[1..info.size - 1]
    end
  end
  
  rest_of_line = line[div_base_informations.size..line.size - 1]
  
  num_brackets = 0
  char_num = 0
  start_brackets = 0
  rest_of_line.each_char do |char|
    if (char == '{')
      if (num_brackets == 0)
        start_brackets = char_num
      end
      num_brackets += 1
    elsif (char == '}')
      num_brackets -= 1
      if (num_brackets == 0)
        params[:dom_params] = process_dom_params(rest_of_line[start_brackets..char_num])
      end
    elsif (num_brackets == 0)
      remaining = rest_of_line[char_num..rest_of_line.size - 1].strip
      if (remaining.size > 0)
        if (char == ' ')
          params[:inside] = remaining
          break
        elsif (char == '=' || char == '!')
          params[:inside_code] = evaluate(remaining)
          break
        end
      end
    end
    char_num += 1
  end
  
  return construct_dom(params)
end

#convert_from_node(code_node, indentation = -1)) ⇒ String

Converts a HamlToStar::CodeNode to executable code.

Parameters:

  • code_node (CodeNode)

    The code tree

Returns:

  • (String)


169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/haml_to_star/compiler.rb', line 169

def convert_from_node(code_node, indentation = -1)
  str = []

  inside = []
  code_node.children.each do |child|
    inside << convert_from_node(child, indentation + 1)
  end
  if (indentation > -1)
    line = code_node.line
    if (line[0] != '-')
      process_code_line_number(str, code_node.line_number)
    end
    if (line[0] == '%' || line[0] == '.' || line[0] == '#')
      dom = convert_dom_element(line)
      if (dom[:self_closing])
        add_content(str, dom[:begin])
      else
        add_content(str, dom[:begin])
        if (inside.size > 0)
          str << inside.join("\n")
        else
          if (dom[:inside])
            add_content(str, dom[:inside])
          end
        end
        add_content(str, dom[:end])
      end
    elsif (line[0] == '=' || line[0] == '!')
      process_inline_code(str, line)
    elsif (line[0] == '-')
      add_code(str, line, inside)
    else
      add_content(str, line.to_json)
    end
  else
    initialize_content(str, inside)
  end
  
  return str.join("\n")
end

#convert_from_string(str) ⇒ String

Converts haml code to executable code. Internally, the function first convert it to a HamlToStar::CodeNode and the calls convert_from_node

Parameters:

  • str (String)

    The haml code

Returns:

  • (String)


66
67
68
69
70
71
72
73
# File 'lib/haml_to_star/compiler.rb', line 66

def convert_from_string(str)
  nb_char_per_indentation = get_indentation_spacing_from_string(str)
  
  @line_number = 0
  code_node = CodeNode.new
  code_node.children = get_code_children_from_string(str, nb_char_per_indentation, 0)
  return convert_from_node(code_node) 
end

#evaluate(line) ⇒ String

How do we what is after = or !=

Parameters:

  • line (String)

    Line to be processed

Returns:

  • (String)


342
343
344
# File 'lib/haml_to_star/compiler.rb', line 342

def evaluate(line)
  raise 'To be defined'
end

#get_code_children_from_string(str, nb_char_per_indentation, nb_indentation_depth) ⇒ Array<CodeNode>

Converts haml code into an array of HamlToStar::CodeNode.

Parameters:

  • str (String)

    The haml code

  • nb_char_per_indentation (Integer)

    Number of spaces defining one unit indentation

  • nb_indentation_depth (Integer)

    Depth of indentation we want to analyse (used by the recursivity)

Returns:



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/haml_to_star/compiler.rb', line 82

def get_code_children_from_string(str, nb_char_per_indentation, nb_indentation_depth)
  temp_str = ''
  children = []
  str.each_line do |line|
    nb_indentations = get_nb_indentation_from_line(line, nb_char_per_indentation)
    if (nb_indentations == nb_indentation_depth)
      code_element = CodeNode.new
      code_element.line = line[nb_indentation_depth * nb_char_per_indentation..line.size]
      if code_element.line[code_element.line.size - 1] == "\n"
        code_element.line = code_element.line[0..code_element.line.size - 2]
      end
      if (temp_str != '')
        children.last.children = get_code_children_from_string(temp_str, nb_char_per_indentation, nb_indentation_depth + 1)
        temp_str = ''
      end
      @line_number += 1
      code_element.line_number = @line_number
      children << code_element
    else
      temp_str += line
    end
  end
  if (temp_str != '')
    children.last.children = get_code_children_from_string(temp_str, nb_char_per_indentation, nb_indentation_depth + 1)
    temp_str = ''
  end
  return children
end

#get_indentation_spacing_from_string(str) ⇒ Integer

From a haml code, determines number of spaces / tabs composes one indentation unit

Parameters:

  • str (String)

    The haml code

Returns:

  • (Integer)


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/haml_to_star/compiler.rb', line 137

def get_indentation_spacing_from_string(str)
  str.each_line do |line|
    nb_char = 0
    line.each_char do |char|
      if is_spacing_character(char)
        nb_char += 1
      else
        break
      end
    end
    if (nb_char != 0)
      return nb_char
    end
  end
  
  return 1
end

#get_nb_indentation_from_line(line, nb_char_per_indentation) ⇒ Integer

From a line in the haml code, determines the number of indentation unit

Parameters:

  • line (String)

    The haml code line

  • nb_char_per_indentation (Integer)

    Number of spaces defining one unit indentation

Returns:

  • (Integer)


117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/haml_to_star/compiler.rb', line 117

def get_nb_indentation_from_line(line, nb_char_per_indentation)
  nb_char = 0
  line.each_char do |char|
    if is_spacing_character(char)
      nb_char += 1
    else
      break;
    end
  end
  if (nb_char % nb_char_per_indentation != 0)
    raise "Bad indentation"
  end
  return nb_char / nb_char_per_indentation
end

#initialize_content(str, content) ⇒ Object

What should be on the header of generated code

Parameters:

  • str (String)

    Result string

  • content (String)

    Generated code



316
317
318
# File 'lib/haml_to_star/compiler.rb', line 316

def initialize_content(str, content)
  raise 'To be defined'
end

#is_spacing_character(char) ⇒ Boolean

Returns true if the character is a space or tab, false otherwise

Parameters:

  • char (String)

    Character to be analysed

Returns:

  • (Boolean)


160
161
162
# File 'lib/haml_to_star/compiler.rb', line 160

def is_spacing_character(char)
  return char == ' ' || char == "\t";
end

#process_code_line_number(str, code_line_number) ⇒ Object

How do we add the current line number into the resulted string

Parameters:

  • str (String)

    Result string

  • code_line_number (String)

    Current line number



350
351
352
# File 'lib/haml_to_star/compiler.rb', line 350

def process_code_line_number(str, code_line_number)
  raise 'To be defined'
end

#process_dom_params(dom_params) ⇒ String

Process dom parameters

Parameters:

  • dom_params (String)

    Dom parameters

Returns:

  • (String)


308
309
310
# File 'lib/haml_to_star/compiler.rb', line 308

def process_dom_params(dom_params)
  raise 'To be defined'
end

#process_inline_code(str, content) ⇒ Object

How do we process lines begining with = or !=

Parameters:

  • line (String)

    Line to be processed



357
358
359
# File 'lib/haml_to_star/compiler.rb', line 357

def process_inline_code(str, content)
  raise 'To be defined'
end