bade 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Bade
5
+ require_relative '../parser'
6
+
7
+ class Parser
8
+ module TagRegexps
9
+ BLOCK_EXPANSION = /\A:\s+/
10
+ OUTPUT_CODE = LineIndicatorRegexps::OUTPUT_BLOCK
11
+ TEXT_START = /\A /
12
+
13
+ PARAMS_ARGS_DELIMITER = /\A\s*,/
14
+ PARAMS_END = /\A\s*\)/
15
+ end
16
+
17
+ # @param [String] tag tag name
18
+ #
19
+ def parse_tag(tag)
20
+ tag = fixed_trailing_colon(tag)
21
+
22
+ if tag.is_a?(AST::Node)
23
+ tag_node = tag
24
+ else
25
+ tag_node = append_node(:tag, add: true)
26
+ tag_node.name = tag
27
+ end
28
+
29
+ parse_tag_attributes
30
+
31
+ case @line
32
+ when TagRegexps::BLOCK_EXPANSION
33
+ # Block expansion
34
+ @line = $'
35
+ parse_line_indicators(add_newline: false)
36
+
37
+ when TagRegexps::OUTPUT_CODE
38
+ # Handle output code
39
+ parse_line_indicators(add_newline: false)
40
+
41
+ when CLASS_TAG_RE
42
+ # Class name
43
+ @line = $'
44
+
45
+ attr_node = append_node(:tag_attr)
46
+ attr_node.name = 'class'
47
+ attr_node.value = fixed_trailing_colon($1).single_quote
48
+
49
+ parse_tag tag_node
50
+
51
+ when ID_TAG_RE
52
+ # Id name
53
+ @line = $'
54
+
55
+ attr_node = append_node(:tag_attr)
56
+ attr_node.name = 'id'
57
+ attr_node.value = fixed_trailing_colon($1).single_quote
58
+
59
+ parse_tag tag_node
60
+
61
+ when TagRegexps::TEXT_START
62
+ # Text content
63
+ @line = $'
64
+ parse_text
65
+
66
+ when ''
67
+ # nothing
68
+
69
+ else
70
+ syntax_error "Unknown symbol after tag definition #{@line}"
71
+ end
72
+ end
73
+
74
+ def parse_tag_attributes
75
+ # Check to see if there is a delimiter right after the tag name
76
+
77
+ # between tag name and attribute must not be space
78
+ # and skip when is nothing other
79
+ return unless @line.start_with?('(')
80
+
81
+ # remove starting bracket
82
+ @line.remove_first!
83
+
84
+ loop do
85
+ case @line
86
+ when CODE_ATTR_RE
87
+ # Value ruby code
88
+ @line = $'
89
+ attr_node = append_node(:tag_attr)
90
+ attr_node.name = $1
91
+ attr_node.value = parse_ruby_code(ParseRubyCodeRegexps::END_PARAMS_ARG)
92
+
93
+ when TagRegexps::PARAMS_ARGS_DELIMITER
94
+ # args delimiter
95
+ @line = $'
96
+ next
97
+
98
+ when TagRegexps::PARAMS_END
99
+ # Find ending delimiter
100
+ @line = $'
101
+ break
102
+
103
+ else
104
+ # Found something where an attribute should be
105
+ @line.lstrip!
106
+ syntax_error('Expected attribute') unless @line.empty?
107
+
108
+ # Attributes span multiple lines
109
+ append_node(:newline)
110
+ syntax_error('Expected closing tag attributes delimiter `)`') if @lines.empty?
111
+ next_line
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Bade
5
+ require_relative '../parser'
6
+
7
+ class Parser
8
+ module TextRegexps
9
+ INTERPOLATION_START = /(\\)?(&|#)\{/
10
+ INTERPOLATION_END = /\A\}/
11
+ end
12
+
13
+ def parse_text
14
+ new_index = @line.index(TextRegexps::INTERPOLATION_START)
15
+
16
+ # the interpolation sequence is not in text, mark whole text as static
17
+ if new_index.nil?
18
+ append_node(:static_text, value: @line)
19
+ return
20
+ end
21
+
22
+ unparsed_part = String.new
23
+
24
+ while (new_index = @line.index(TextRegexps::INTERPOLATION_START))
25
+ if $1.nil?
26
+ static_part = unparsed_part + @line.remove_first!(new_index)
27
+ append_node(:static_text, value: static_part)
28
+
29
+ @line.remove_first!(2) # #{ or &{
30
+
31
+ dynamic_part = parse_ruby_code(TextRegexps::INTERPOLATION_END)
32
+ node = append_node(:output, value: dynamic_part)
33
+ node.escaped = $2 == '&'
34
+
35
+ @line.remove_first! # ending }
36
+
37
+ unparsed_part = String.new
38
+ else
39
+ unparsed_part << @line.remove_first!(new_index)
40
+ @line.remove_first! # symbol \
41
+ unparsed_part << @line.remove_first!(2) # #{ or &{
42
+ end
43
+ end
44
+
45
+ # add the rest of line
46
+ append_node(:static_text, value: unparsed_part + @line) unless @line.empty?
47
+ end
48
+
49
+ def parse_text_block(first_line, text_indent = nil)
50
+ if !first_line || first_line.empty?
51
+ text_indent = nil
52
+ else
53
+ @line = first_line
54
+ parse_text
55
+ end
56
+
57
+ until @lines.empty?
58
+ if @lines.first.blank?
59
+ next_line
60
+ append_node(:newline)
61
+ else
62
+ indent = get_indent(@lines.first)
63
+ break if indent <= @indents.last
64
+
65
+ next_line
66
+
67
+ @line.remove_indent!(text_indent ? text_indent : indent, @tabsize)
68
+
69
+ parse_text
70
+
71
+ # The indentation of first line of the text block
72
+ # determines the text base indentation.
73
+ text_indent ||= indent
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -50,8 +50,8 @@ module Bade
50
50
  end
51
51
 
52
52
  content = {
53
- source_file_path: source_file_path,
54
- code_string: code_string,
53
+ source_file_path: source_file_path,
54
+ code_string: code_string,
55
55
  }.to_yaml
56
56
 
57
57
  file.write(content)
@@ -22,14 +22,14 @@ module Bade
22
22
  # @param [String] reference_path reference file from which is load performed
23
23
  # @param [String] msg standard message
24
24
  #
25
- def initialize(loading_path, reference_path, msg=nil)
25
+ def initialize(loading_path, reference_path, msg = nil)
26
26
  super(msg)
27
27
  @loading_path = loading_path
28
28
  @reference_path = reference_path
29
29
  end
30
30
  end
31
31
 
32
- TEMPLATE_FILE_NAME = '(__template__)'
32
+ TEMPLATE_FILE_NAME = '(__template__)'.freeze
33
33
 
34
34
  # @return [String]
35
35
  #
@@ -167,7 +167,8 @@ module Bade
167
167
  # ----------------------------------------------------------------------------- #
168
168
  # Render
169
169
 
170
- # @param [Binding] binding custom binding for evaluating the template, but it is not recommended to use, use :locals and #with_locals instead
170
+ # @param [Binding] binding custom binding for evaluating the template, but it is not recommended to use,
171
+ # use :locals and #with_locals instead
171
172
  # @param [String] new_line newline string, default is \n
172
173
  # @param [String] indent indent string, default is two spaces
173
174
  #
@@ -177,8 +178,8 @@ module Bade
177
178
  self.lambda_binding = binding unless binding.nil? # backward compatibility
178
179
 
179
180
  run_vars = {
180
- Generator::NEW_LINE_NAME.to_sym => new_line,
181
- Generator::BASE_INDENT_NAME.to_sym => indent,
181
+ Generator::NEW_LINE_NAME.to_sym => new_line,
182
+ Generator::BASE_INDENT_NAME.to_sym => indent,
182
183
  }
183
184
  run_vars.reject! { |_key, value| value.nil? } # remove nil values
184
185
 
@@ -219,7 +220,8 @@ module Bade
219
220
  document
220
221
  end
221
222
 
222
- # Tries to find file with name, if no file could be found or there are multiple files matching the name error is raised
223
+ # Tries to find file with name, if no file could be found or there are multiple files matching the name error is
224
+ # raised
223
225
  #
224
226
  # @param [String] name name of the file that should be found
225
227
  # @param [String] reference_path path to file from which is loading/finding
@@ -229,25 +231,28 @@ module Bade
229
231
  def _find_file!(name, reference_path)
230
232
  sub_path = File.expand_path(name, File.dirname(reference_path))
231
233
 
232
- if File.exists?(sub_path)
234
+ if File.exist?(sub_path)
233
235
  return if sub_path.end_with?('.rb') # handled in Generator
234
236
  sub_path
235
237
  else
236
238
  bade_path = "#{sub_path}.bade"
237
239
  rb_path = "#{sub_path}.rb"
238
240
 
239
- bade_exist = File.exists?(bade_path)
240
- rb_exist = File.exists?(rb_path)
241
- relative = Pathname.new(reference_path).relative_path_from(Pathname.new(File.dirname(self.file_path))).to_s
241
+ bade_exist = File.exist?(bade_path)
242
+ rb_exist = File.exist?(rb_path)
243
+ relative = Pathname.new(reference_path).relative_path_from(Pathname.new(File.dirname(file_path))).to_s
242
244
 
243
245
  if bade_exist && rb_exist
244
- raise LoadError.new(name, reference_path, "Found both .bade and .rb files for `#{name}` in file #{relative}, change the import path so it references uniq file.")
246
+ message = "Found both .bade and .rb files for `#{name}` in file #{relative}, "\
247
+ 'change the import path so it references uniq file.'
248
+ raise LoadError.new(name, reference_path, message)
245
249
  elsif bade_exist
246
250
  return bade_path
247
251
  elsif rb_exist
248
252
  return # handled in Generator
249
253
  else
250
- raise LoadError.new(name, reference_path, "Can't find file matching name `#{name}` referenced from file #{relative}")
254
+ message = "Can't find file matching name `#{name}` referenced from file #{relative}"
255
+ raise LoadError.new(name, reference_path, message)
251
256
  end
252
257
  end
253
258
  end
@@ -7,19 +7,17 @@ class Array
7
7
  #
8
8
  # @return [Fixnum]
9
9
  #
10
- def rindex_last_matching(&block)
10
+ def rindex_last_matching
11
11
  return nil if empty?
12
12
 
13
13
  index = nil
14
14
 
15
15
  current_index = count - 1
16
16
  reverse_each do |item|
17
- if block.call(item)
18
- index = current_index
19
- current_index -= 1
20
- else
21
- break
22
- end
17
+ break unless yield item
18
+
19
+ index = current_index
20
+ current_index -= 1
23
21
  end
24
22
 
25
23
  index
@@ -29,15 +27,13 @@ class Array
29
27
  #
30
28
  # @return [Fixnum] count of items
31
29
  #
32
- def rcount_matching(&block)
30
+ def rcount_matching
33
31
  count = 0
34
32
 
35
33
  reverse_each do |item|
36
- if block.call(item)
37
- count += 1
38
- else
39
- break
40
- end
34
+ break unless yield item
35
+
36
+ count += 1
41
37
  end
42
38
 
43
39
  count
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :nodoc:
3
4
  class String
4
- SPACE_CHAR = ' '
5
- TAB_CHAR = "\t"
5
+ SPACE_CHAR = ' '.freeze
6
+ TAB_CHAR = "\t".freeze
6
7
 
7
8
  # Creates new string surrounded by single quotes
8
9
  #
@@ -14,7 +15,7 @@ class String
14
15
 
15
16
 
16
17
  def blank?
17
- strip.length == 0
18
+ strip.empty?
18
19
  end
19
20
 
20
21
 
@@ -37,16 +38,14 @@ class String
37
38
 
38
39
  def __chars_count_for_indent(indent, tabsize)
39
40
  count = 0
40
- self.each_char do |char|
41
+ each_char do |char|
41
42
  break if indent <= 0
42
43
 
43
44
  case char
44
45
  when SPACE_CHAR
45
46
  indent -= 1
46
47
  when TAB_CHAR
47
- if indent - tabsize < 0
48
- raise StandardError, 'malformed tabs'
49
- end
48
+ raise StandardError, 'malformed tabs' if indent - tabsize < 0
50
49
 
51
50
  indent -= tabsize
52
51
  else
@@ -88,7 +87,7 @@ class String
88
87
  def get_indent(tabsize)
89
88
  count = 0
90
89
 
91
- self.each_char do |char|
90
+ each_char do |char|
92
91
  if char == SPACE_CHAR
93
92
  count += 1
94
93
  elsif char == TAB_CHAR
@@ -101,4 +100,12 @@ class String
101
100
  count
102
101
  end
103
102
 
103
+ # source: http://apidock.com/rails/String/strip_heredoc
104
+ # @return [String]
105
+ #
106
+ def strip_heredoc
107
+ min_val = scan(/^[ \t]*(?=\S)/).min
108
+ indent = (min_val && min_val.size) || 0
109
+ gsub(/^[ \t]{#{indent}}/, '')
110
+ end
104
111
  end
@@ -57,11 +57,9 @@ module Bade
57
57
  end
58
58
 
59
59
  def call!(*args)
60
- if @block.nil?
61
- raise MissingBlockDefinitionError.new(name, :call)
62
- else
63
- render_binding.__buff.concat(@block.call(*args))
64
- end
60
+ raise MissingBlockDefinitionError.new(name, :call) if @block.nil?
61
+
62
+ render_binding.__buff.concat(@block.call(*args))
65
63
  end
66
64
 
67
65
  # --- Rendering methods
@@ -75,11 +73,9 @@ module Bade
75
73
  end
76
74
 
77
75
  def render!(*args)
78
- if @block.nil?
79
- raise MissingBlockDefinitionError.new(name, :render)
80
- else
81
- @block.call(*args).join
82
- end
76
+ raise MissingBlockDefinitionError.new(name, :render) if @block.nil?
77
+
78
+ @block.call(*args).join
83
79
  end
84
80
  end
85
81
  end
@@ -9,7 +9,8 @@ module Bade
9
9
  block.call(blocks, *args)
10
10
  rescue ArgumentError => e
11
11
  case e.message
12
- when /\Awrong number of arguments \(given ([0-9]+), expected ([0-9]+)\)\Z/, /\Awrong number of arguments \(([0-9]+) for ([0-9]+)\)\Z/
12
+ when /\Awrong number of arguments \(given ([0-9]+), expected ([0-9]+)\)\Z/,
13
+ /\Awrong number of arguments \(([0-9]+) for ([0-9]+)\)\Z/
13
14
  # handle incorrect parameters count
14
15
 
15
16
  # minus one, because first argument is always hash of blocks
@@ -80,17 +80,17 @@ module Bade
80
80
  # @return [String]
81
81
  #
82
82
  def __html_escaped(text)
83
- text.sub('&', '&amp;')
84
- .sub('<', '&lt;')
85
- .sub('>', '&gt;')
86
- .sub('"', '&quot;')
83
+ text.gsub('&', '&amp;')
84
+ .gsub('<', '&lt;')
85
+ .gsub('>', '&gt;')
86
+ .gsub('"', '&quot;')
87
87
  end
88
88
 
89
89
  def __tag_render_attribute(name, *values)
90
90
  values = values.compact
91
91
  return if values.empty?
92
92
 
93
- %Q{ #{name}="#{values.join(' ')}"}
93
+ %( #{name}="#{values.join(' ')}")
94
94
  end
95
95
  end
96
96
  end