hotcell 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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 &&