bade 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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