hotcell 0.0.1 → 0.1.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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -1
  3. data/.rspec +1 -0
  4. data/.rvmrc +1 -1
  5. data/.travis.yml +7 -0
  6. data/Gemfile +4 -1
  7. data/README.md +361 -2
  8. data/Rakefile +28 -6
  9. data/ext/lexerc/extconf.rb +3 -0
  10. data/ext/lexerc/lexerc.c +618 -0
  11. data/ext/lexerc/lexerc.h +20 -0
  12. data/ext/lexerc/lexerc.rl +167 -0
  13. data/hotcell.gemspec +8 -7
  14. data/lib/hotcell/commands/case.rb +59 -0
  15. data/lib/hotcell/commands/cycle.rb +38 -0
  16. data/lib/hotcell/commands/for.rb +70 -0
  17. data/lib/hotcell/commands/if.rb +51 -0
  18. data/lib/hotcell/commands/include.rb +21 -0
  19. data/lib/hotcell/commands/scope.rb +13 -0
  20. data/lib/hotcell/commands/unless.rb +23 -0
  21. data/lib/hotcell/commands.rb +13 -0
  22. data/lib/hotcell/config.rb +33 -6
  23. data/lib/hotcell/context.rb +40 -7
  24. data/lib/hotcell/errors.rb +37 -28
  25. data/lib/hotcell/extensions.rb +4 -0
  26. data/lib/hotcell/lexer.rb +19 -635
  27. data/lib/hotcell/lexerr.rb +572 -0
  28. data/lib/hotcell/lexerr.rl +137 -0
  29. data/lib/hotcell/node/assigner.rb +1 -5
  30. data/lib/hotcell/node/block.rb +17 -40
  31. data/lib/hotcell/node/command.rb +29 -22
  32. data/lib/hotcell/node/hasher.rb +1 -1
  33. data/lib/hotcell/node/summoner.rb +2 -6
  34. data/lib/hotcell/node/tag.rb +10 -7
  35. data/lib/hotcell/node.rb +12 -1
  36. data/lib/hotcell/parser.rb +474 -408
  37. data/lib/hotcell/parser.y +175 -117
  38. data/lib/hotcell/resolver.rb +44 -0
  39. data/lib/hotcell/source.rb +35 -0
  40. data/lib/hotcell/template.rb +15 -6
  41. data/lib/hotcell/version.rb +1 -1
  42. data/lib/hotcell.rb +15 -10
  43. data/spec/data/templates/simple.hc +1 -0
  44. data/spec/lib/hotcell/commands/case_spec.rb +39 -0
  45. data/spec/lib/hotcell/commands/cycle_spec.rb +29 -0
  46. data/spec/lib/hotcell/commands/for_spec.rb +65 -0
  47. data/spec/lib/hotcell/commands/if_spec.rb +35 -0
  48. data/spec/lib/hotcell/commands/include_spec.rb +39 -0
  49. data/spec/lib/hotcell/commands/scope_spec.rb +16 -0
  50. data/spec/lib/hotcell/commands/unless_spec.rb +23 -0
  51. data/spec/lib/hotcell/config_spec.rb +35 -10
  52. data/spec/lib/hotcell/context_spec.rb +58 -18
  53. data/spec/lib/hotcell/lexer_spec.rb +37 -28
  54. data/spec/lib/hotcell/node/block_spec.rb +28 -56
  55. data/spec/lib/hotcell/node/command_spec.rb +7 -31
  56. data/spec/lib/hotcell/node/tag_spec.rb +16 -0
  57. data/spec/lib/hotcell/parser_spec.rb +152 -123
  58. data/spec/lib/hotcell/resolver_spec.rb +28 -0
  59. data/spec/lib/hotcell/source_spec.rb +41 -0
  60. data/spec/lib/hotcell/template_spec.rb +47 -4
  61. data/spec/lib/hotcell_spec.rb +2 -1
  62. data/spec/spec_helper.rb +6 -2
  63. metadata +54 -24
  64. data/lib/hotcell/.DS_Store +0 -0
  65. data/lib/hotcell/lexer.rl +0 -299
  66. data/misc/rage.rl +0 -1999
  67. data/misc/unicode2ragel.rb +0 -305
@@ -1,22 +1,27 @@
1
1
  module Hotcell
2
2
  class Block < Hotcell::Command
3
- class_attribute :_subcommands, instance_writter: false
4
- self._subcommands = []
3
+ class_attribute :subcommands, instance_writter: false, instance_reader: false
4
+ self.subcommands = {}
5
5
 
6
- def self.subcommands *names
7
- if names.any?
8
- self._subcommands = _subcommands + names.flatten.map(&:to_s)
6
+ def self.subcommand name_or_hash, &block
7
+ if name_or_hash.is_a? Hash
8
+ self.subcommands = subcommands.merge(name_or_hash.stringify_keys)
9
9
  else
10
- _subcommands
10
+ subcommand name_or_hash => Class.new(Hotcell::Command, &block)
11
11
  end
12
12
  end
13
13
 
14
- def optimize
15
- if klass = Hotcell.blocks[name]
16
- klass.new name, *children, options
17
- else
18
- self
14
+ def validate!
15
+ subcommands.each do |subcommand|
16
+ raise Hotcell::BlockError.new(
17
+ "Unexpected subcommand `#{subcommand.name}` for `#{name}` command",
18
+ *subcommand.position_info
19
+ ) unless self.class.subcommands.key?(subcommand.name)
19
20
  end
21
+
22
+ super
23
+
24
+ subcommands.each(&:validate!)
20
25
  end
21
26
 
22
27
  def subnodes
@@ -24,35 +29,7 @@ module Hotcell
24
29
  end
25
30
 
26
31
  def subcommands
27
- subnodes.select { |node| node.is_a?(Hash) }
28
- end
29
-
30
- def validate!
31
- valid = subcommands.map { |subcommand| subcommand[:name] } - _subcommands == []
32
- raise Hotcell::Errors::BlockError.new 'Invalid block syntax' unless valid
33
- end
34
-
35
- def process context, subnodes, *args
36
- end
37
-
38
- def render context
39
- context.safe do
40
- subnodes = render_subnodes(context)
41
- values = render_nodes(context, children)
42
- concat context, process(context, subnodes, *values)
43
- end
44
- end
45
-
46
- def render_subnodes context
47
- subnodes.map do |node|
48
- if node.is_a?(Hash)
49
- subcommand = { name: node[:name] }
50
- subcommand.merge!(args: node[:args].render(context)) if node[:args]
51
- subcommand
52
- else
53
- node.render(context)
54
- end
55
- end
32
+ subnodes.select { |node| node.is_a?(Hotcell::Command) }
56
33
  end
57
34
  end
58
35
  end
@@ -1,22 +1,39 @@
1
1
  module Hotcell
2
2
  class Command < Hotcell::Node
3
- attr_reader :mode, :assign
3
+ class_attribute :_validations
4
+ self._validations = {}
4
5
 
5
- def initialize *_
6
- super
7
- @mode = options[:mode] || :normal
8
- @assign = options[:assign]
9
- end
10
-
11
- def optimize
12
- if klass = Hotcell.commands[name]
13
- klass.new name, *children, options
6
+ def self.validate_arguments_count options
7
+ arguments_count = case options
8
+ when Hash
9
+ Range.new(options[:min].to_i,
10
+ options[:max].present? ? options[:max].to_i : Float::INFINITY)
11
+ when Range
12
+ options
14
13
  else
15
- self
14
+ options.to_i
16
15
  end
16
+
17
+ self._validations = _validations.merge(arguments_count: arguments_count)
18
+ end
19
+
20
+ def validate_arguments_count!
21
+ return unless _validations.key?(:arguments_count)
22
+
23
+ args_count = children.count
24
+ valid_args_count = _validations[:arguments_count]
25
+
26
+ valid = valid_args_count.is_a?(Integer) ?
27
+ args_count == valid_args_count : valid_args_count.include?(args_count)
28
+
29
+ raise Hotcell::ArgumentError.new(
30
+ "Wrond number of arguments for `#{name}` (#{args_count} for #{valid_args_count})",
31
+ *position_info
32
+ ) unless valid
17
33
  end
18
34
 
19
35
  def validate!
36
+ validate_arguments_count!
20
37
  end
21
38
 
22
39
  def process context, *args
@@ -24,17 +41,7 @@ module Hotcell
24
41
 
25
42
  def render context
26
43
  context.safe do
27
- concat context, process(context, *render_nodes(context, children))
28
- end
29
- end
30
-
31
- def concat context, result
32
- context[assign] = result if assign
33
- case mode
34
- when :normal
35
- result
36
- else
37
- ''
44
+ process(context, *render_children(context))
38
45
  end
39
46
  end
40
47
  end
@@ -1,6 +1,6 @@
1
1
  module Hotcell
2
2
  class Hasher < Hotcell::Node
3
- def render context, *values
3
+ def process context, *values
4
4
  Hash[values]
5
5
  end
6
6
  end
@@ -1,11 +1,7 @@
1
1
  module Hotcell
2
2
  class Summoner < Hotcell::Node
3
- def initialize *attrs
4
- super :METHOD, *attrs
5
- end
6
-
7
- def process context, object, method, *arguments
8
- (object.to_manipulator || context).manipulator_invoke(method, *arguments)
3
+ def process context, target = nil, *arguments
4
+ (target ? target.to_manipulator : context).manipulator_invoke(name, *arguments)
9
5
  end
10
6
  end
11
7
  end
@@ -13,13 +13,16 @@ module Hotcell
13
13
 
14
14
  def render context
15
15
  context.safe do
16
- values = render_nodes(context, children)
17
- case mode
18
- when :normal
19
- process context, *values
20
- else
21
- ''
22
- end
16
+ concat context, process(context, *render_children(context))
17
+ end
18
+ end
19
+
20
+ def concat context, result
21
+ case mode
22
+ when :normal
23
+ result
24
+ else
25
+ ''
23
26
  end
24
27
  end
25
28
  end
data/lib/hotcell/node.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  module Hotcell
2
2
  class Node
3
3
  attr_accessor :name, :children, :options
4
+ attr_reader :position, :source
4
5
 
5
6
  def self.build *args
6
7
  new(*args).optimize
@@ -9,9 +10,15 @@ module Hotcell
9
10
  def initialize name, *args
10
11
  @name = name
11
12
  @options = args.extract_options!
13
+ @source = @options.delete(:source)
14
+ @position = @options.delete(:position)
12
15
  @children = args
13
16
  end
14
17
 
18
+ def position_info
19
+ source.info(position).values_at(:line, :column)
20
+ end
21
+
15
22
  def optimize
16
23
  self
17
24
  end
@@ -21,7 +28,7 @@ module Hotcell
21
28
  end
22
29
 
23
30
  def render context
24
- process context, *render_nodes(context, children)
31
+ process context, *render_children(context)
25
32
  end
26
33
 
27
34
  def process context, *values
@@ -34,6 +41,10 @@ module Hotcell
34
41
  end
35
42
  end
36
43
 
44
+ def render_children context
45
+ render_nodes context, children
46
+ end
47
+
37
48
  def == other
38
49
  other.is_a?(self.class) &&
39
50
  name == other.name &&