eggshell 0.8.3 → 1.0.0

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.
@@ -13,13 +13,14 @@ module Eggshell::Bundles::Loader
13
13
  end
14
14
 
15
15
  class LoaderMacro
16
+ include Eggshell::MacroHandler
16
17
  def set_processor(proc)
17
18
  @proc = proc
18
- proc.register_macro(self, *%w(gems files bundles vars))
19
+ proc.add_macro_handler(self, *%w(gems files bundles vars))
19
20
  end
20
21
 
21
- def process(buffer, macname, args, lines, depth)
22
- if macname == 'gems'
22
+ def process(type, args, lines, out, call_depth = 0)
23
+ if type == 'gems'
23
24
  args.each do |gemname|
24
25
  begin
25
26
  require gemname
@@ -28,7 +29,7 @@ module Eggshell::Bundles::Loader
28
29
  @proc._warn("could not load gem: #{gemname}")
29
30
  end
30
31
  end
31
- elsif macname == 'files'
32
+ elsif type == 'files'
32
33
  args.each do |file|
33
34
  begin
34
35
  if file[0] == '/'
@@ -45,7 +46,7 @@ module Eggshell::Bundles::Loader
45
46
  @proc._warn("could not load file: #{file}")
46
47
  end
47
48
  end
48
- elsif macname == 'bundles'
49
+ elsif type == 'bundles'
49
50
  args.each do |bundle|
50
51
  Eggshell::Bundles::Registry.attach_bundle(bundle, @proc.vars[:target])
51
52
  end
@@ -5,6 +5,7 @@ class Eggshell::ExpressionEvaluator
5
5
  REGEX_EXPR_PLACEHOLDERS = /(\\|\$\[|\$\{|\]|\}|\+|\-|>|<|=|\s+|\(|\)|\*|\/`)/
6
6
  REGEX_EXPR_STATEMENT = /(\(|\)|,|\[|\]|\+|-|\*|\/|%|<=|>=|==|<|>|"|'|\s+|\\|\{|\}|:|\?)/
7
7
  REGEX_OPERATORS = /\+|-|\*|\/|%|<=|>=|<|>|==|!=|&&|\|\||&|\|/
8
+ REGEX_VARNAME = /[\w\d]+/
8
9
 
9
10
  LOG_OP = 2
10
11
  LOG_LEVEL = 0
@@ -345,12 +346,19 @@ class Eggshell::ExpressionEvaluator
345
346
  term = nil
346
347
  term_state = nil
347
348
  elsif tok == '{'
348
- if state[-1] == :nil && stack[0][-1][0] == :fn
349
+ if state[-1] == :nil #&& stack[0][-1][0] == :fn
349
350
  delim = '{'
350
351
  while toks[i]
351
352
  delim += toks[i]
352
353
  i += 1
353
354
  end
355
+
356
+ # @todo is it safe to do stack[0]? stick to ptr instead?
357
+ if term
358
+ stack[0] << term_val(term, term_state == :quote)
359
+ term = nil
360
+ term_state = nil
361
+ end
354
362
  stack[0] << [:brace_op, delim]
355
363
  break
356
364
  end
@@ -494,7 +502,8 @@ class Eggshell::ExpressionEvaluator
494
502
  # look-ahead to build variable reference
495
503
  ntok = toks[i]
496
504
  while ntok
497
- if ntok != ',' && ntok != ':' && ntok != '(' && ntok != ')' && ntok != '}' && !ntok.match(REGEX_OPERATORS)
505
+ #if ntok != ',' && ntok != ':' && ntok != '(' && ntok != ')' && ntok != '}' && ntok != '{' && !ntok.match(REGEX_OPERATORS)
506
+ if ntok.match(REGEX_VARNAME)
498
507
  if ntok != ' ' && ntok != "\t"
499
508
  term += ntok
500
509
  end
@@ -506,7 +515,7 @@ class Eggshell::ExpressionEvaluator
506
515
  end
507
516
  end
508
517
  end
509
-
518
+
510
519
  # @todo validate completeness of state (e.g. no omitted parenthesis)
511
520
  if state[1] || term
512
521
  _transition.call(state[-1])
@@ -690,6 +699,7 @@ class Eggshell::ExpressionEvaluator
690
699
  def self.expr_eval_op(op, lterm, rterm)
691
700
  ret = nil
692
701
  #$stderr.write "** #{lterm.inspect} ( #{op} ) #{rterm.inspect}\n"
702
+
693
703
  case op
694
704
  when '=='
695
705
  ret = lterm == rterm
@@ -0,0 +1,40 @@
1
+ # Interface for handling inline formatting. Markup follows this general structure:
2
+ # {{open_delim + string + close_delim}}. Opening and closing delimiters are defined
3
+ # by the handler.
4
+ module Eggshell::FormatHandler
5
+ def set_processor(proc, opts = nil)
6
+ @eggopts = opts || {}
7
+ @eggshell = proc
8
+ @eggshell.add_format_handler(self, @fmt_delimeters)
9
+ if self.respond_to?(:post_processor)
10
+ post_processor
11
+ end
12
+ end
13
+
14
+ # @param String tag The opening delimeter.
15
+ # @param String str The string between delimeters.
16
+ def format(tag, str)
17
+ end
18
+
19
+ module Utils
20
+ # Parses arguments in the form: `arg0 ; arg1 ; ...|att=val|att2=val|...`
21
+ #
22
+ # The first portion is the direct argument. For instance, a link like
23
+ # `[~ link ; text ~]` or an image like `[! src ; alt !]`. The remaining
24
+ # piped args are key-value pairs (use `\\|` to escape) which might
25
+ # be embedded in the tag or signal some further transformations.
26
+ #
27
+ # @return An array where the last element is always a {{Hash}}
28
+ def parse_args(arg_str)
29
+ raw_args = arg_str.split(/(?<!\\)\|/)
30
+ args = raw_args.shift.split(/ ; /)
31
+ map = {}
32
+ raw_args.each do |rarg|
33
+ k, v = rarg.split('=', 2)
34
+ map[k] = v
35
+ end
36
+ args << map
37
+ args
38
+ end
39
+ end
40
+ end
@@ -17,24 +17,30 @@
17
17
  # misc content
18
18
  # @end_block_macro
19
19
  #
20
- #
21
20
  module Eggshell::MacroHandler
22
- def set_processor(proc)
23
- end
21
+ include Eggshell::BaseHandler
22
+ include Eggshell::ProcessHandler
23
+
24
+
25
+ COLLECT_NORMAL = :collect_normal
26
+ COLLECT_RAW_MACRO = :collect_raw_macro
27
+ COLLECT_RAW = :collect_raw
24
28
 
25
- def process(buffer, macname, args, lines, indent)
29
+ # Indicates how to process lines contained with in the macro. {{COLLECT_NORMAL}}
30
+ # continues to evaluate block and macro content. {{COLLECT_RAW_MACRO}} collects
31
+ # all lines as raw unless a macro is encountered. {{COLLECT_RAW}} collects all
32
+ # lines as raw, regardless of nested macros.
33
+ # @todo needed?
34
+ def collection_type(macro)
35
+ COLLECT_NORMAL
26
36
  end
27
37
 
28
38
  module Defaults
29
39
  class NoOpHandler
30
40
  include Eggshell::MacroHandler
31
41
 
32
- def set_processor(proc)
33
- @proc = proc
34
- end
35
-
36
- def process(buffer, macname, args, lines, indent)
37
- @proc._warn("couldn't find macro: #{macname}")
42
+ def process(name, args, lines, out, call_depth = 0)
43
+ @eggshell._warn("not implemented: #{macname}")
38
44
  end
39
45
  end
40
46
  end
@@ -0,0 +1,149 @@
1
+ # Holds a hierarchical collection of blocks and macros. The tree follows
2
+ # this structure:
3
+ #
4
+ # pre. [
5
+ # String*,
6
+ # [:block, 'block_name', [], line_start]* # last entry is array of Eggshell::Line,
7
+ # [:macro, 'macro_name', {}, [
8
+ # __repeat_of_parse_tree
9
+ # ]
10
+ # ], line_start*
11
+ # ]
12
+ class Eggshell::ParseTree
13
+ BH = Eggshell::BlockHandler
14
+
15
+ IDX_TYPE = 0
16
+ IDX_NAME = 1
17
+ IDX_ARGS = 2
18
+ IDX_LINES = 3
19
+ IDX_LINES_START = 4
20
+ IDX_LINES_END = 5
21
+
22
+ def initialize
23
+ #@eggshell = eggshell
24
+ @modes = [:nil]
25
+ @tree = []
26
+ @lines = []
27
+ @macro_delims = []
28
+ @macro_open = []
29
+ @macro_ptr = []
30
+ @ptr = @tree
31
+ end
32
+
33
+ def new_macro(line_obj, line_start)
34
+ line = line_obj.line
35
+ macro, args, delim = Eggshell::Processor.parse_macro_start(line)
36
+
37
+ push_block
38
+
39
+ if delim
40
+ @modes << :macro
41
+ @macro_delims << delim.reverse.gsub('[', ']').gsub('(', ')').gsub('{', '}')
42
+ @macro_open << line
43
+ @macro_ptr << @ptr
44
+ # set ptr to entry's tree
45
+ entry = [:macro, macro, args, [], line_start]
46
+ @ptr << entry
47
+ @ptr = entry[IDX_LINES]
48
+ else
49
+ @ptr << [:macro, macro, args, [], line_start]
50
+ end
51
+ end
52
+
53
+ def macro_delim_match(line_obj, line_num)
54
+ if @macro_delims[-1] == line_obj.line
55
+ if @modes[-1] == :block
56
+ push_block
57
+ end
58
+ @macro_delims.pop
59
+ @macro_open.pop
60
+ @ptr = @macro_ptr.pop
61
+ @ptr[-1] << line_num
62
+ last_mode = @modes.pop
63
+ return true
64
+ end
65
+ return false
66
+ end
67
+
68
+ def new_block(handler, type, line_obj, consume_mode, line_start)
69
+ block_type, args, line = Eggshell::Processor.parse_block_start(line_obj.line)
70
+ nline = Eggshell::Line.new(line, line_obj.tab_str, line_obj.indent_lvl, line_obj.line_num)
71
+
72
+ if consume_mode != BH::DONE
73
+ @modes << :block
74
+ if line != ''
75
+ @lines << nline
76
+ line_start -= 1
77
+ end
78
+ @cur_block = [handler, type, args, line_start]
79
+ if consume_mode == BH::COLLECT_RAW
80
+ mode = :raw
81
+ else consume_mode == BH::COLLECT
82
+ mode = :block
83
+ end
84
+ else
85
+ @ptr << [:block, type, args, [nline], line_start]
86
+ end
87
+ end
88
+
89
+ def push_block
90
+ if @modes[-1] == :block
91
+ if @cur_block
92
+ line_end = @cur_block[3]
93
+ line_end = @lines[-1].line_num if @lines[-1]
94
+ @ptr << [:block, @cur_block[1], @cur_block[2], @lines, @cur_block[3], line_end]
95
+ @lines = []
96
+ @cur_block[0].reset
97
+ @cur_block = nil
98
+ end
99
+ @modes.pop
100
+ end
101
+ end
102
+
103
+ def collect(line_obj)
104
+ more = @cur_block[0].continue_with(line_obj.line)
105
+ if more != BH::RETRY
106
+ @lines << line_obj
107
+ if more == BH::DONE
108
+ push_block
109
+ end
110
+ else
111
+ push_block
112
+ end
113
+ more
114
+ end
115
+
116
+ def raw_line(line_obj)
117
+ @ptr << line_obj
118
+ end
119
+
120
+ def tree
121
+ @tree.clone
122
+ end
123
+
124
+ # @todo return macro_open
125
+
126
+ def mode
127
+ @modes[-1]
128
+ end
129
+
130
+ # Does basic output of parse tree structure to visually inspect parsed info.
131
+ def self.walk(struct = nil, indent = 0, out = nil)
132
+ out = $stdout if !out
133
+ struct.each do |row|
134
+ if row.is_a?(Eggshell::Line)
135
+ out.write "#{' '*indent}#{row.to_s.inspect} ##{row.line_num}\n"
136
+ elsif row.is_a?(Array)
137
+ if row[0] == :macro
138
+ out.write "#{' '*indent}@#{row[1]}(#{row[2].inspect}) | end=#{row[-1]}\n"
139
+ walk(row[3], indent + 1, out)
140
+ elsif row[0] == :block
141
+ out.write "#{' '*indent}#{row[1]}(#{row[2].inspect}) | end=#{row[-1]}\n"
142
+ walk(row[3], indent + 1, out)
143
+ end
144
+ else
145
+ out.write "#{' '*indent}#{row.inspect} ?\n"
146
+ end
147
+ end
148
+ end
149
+ end
@@ -1,28 +1,15 @@
1
1
  # Holds things like variables, line/char count, and other useful information for a {{Processor}} instance.
2
2
  class Eggshell::ProcessorContext
3
3
  def initialize
4
- @vars = {:references => {}, :toc => [], :include_paths => [], 'log.level' => '1'}
4
+ @vars = {:references => {}, :toc => [], :include_paths => [], 'log.level' => 1}
5
5
  @funcs = {}
6
6
  @macros = {}
7
- @blocks = {}
7
+ @blocks = []
8
+ @blocks_map = {}
8
9
  @block_params = {}
9
10
  @expr_cache = {}
10
-
11
- # keeps track of line counters based on include
12
- @lcounters = [Eggshell::LineCounter.new]
11
+ @fmt_handlers = {}
13
12
  end
14
13
 
15
- attr_reader :vars, :funcs, :macros, :blocks, :block_params, :expr_cache
16
-
17
- def push_line_counter
18
- @lcounters << Eggshell::LineCounter.new
19
- end
20
-
21
- def pop_line_counter
22
- @lcounters.pop
23
- end
24
-
25
- def line_counter
26
- @lcounters[-1]
27
- end
14
+ attr_reader :vars, :funcs, :macros, :blocks, :blocks_map, :block_params, :expr_cache, :fmt_handlers
28
15
  end