template-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +70 -0
  6. data/lib/code/node/base_10_decimal.rb +27 -0
  7. data/lib/code/node/base_10_integer.rb +23 -0
  8. data/lib/code/node/base_10_number.rb +19 -0
  9. data/lib/code/node/base_16_number.rb +19 -0
  10. data/lib/code/node/base_2_number.rb +19 -0
  11. data/lib/code/node/base_8_number.rb +19 -0
  12. data/lib/code/node/boolean.rb +13 -0
  13. data/lib/code/node/call.rb +19 -0
  14. data/lib/code/node/code.rb +19 -0
  15. data/lib/code/node/dictionnary.rb +18 -0
  16. data/lib/code/node/dictionnary_key_value.rb +23 -0
  17. data/lib/code/node/list.rb +13 -0
  18. data/lib/code/node/name.rb +17 -0
  19. data/lib/code/node/nothing.rb +12 -0
  20. data/lib/code/node/number.rb +23 -0
  21. data/lib/code/node/statement.rb +31 -0
  22. data/lib/code/node/string.rb +17 -0
  23. data/lib/code/node.rb +4 -0
  24. data/lib/code/object/boolean.rb +28 -0
  25. data/lib/code/object/decimal.rb +31 -0
  26. data/lib/code/object/dictionnary.rb +32 -0
  27. data/lib/code/object/integer.rb +29 -0
  28. data/lib/code/object/list.rb +37 -0
  29. data/lib/code/object/nothing.rb +22 -0
  30. data/lib/code/object/string.rb +30 -0
  31. data/lib/code/object.rb +11 -0
  32. data/lib/code/parser/boolean.rb +14 -0
  33. data/lib/code/parser/call.rb +16 -0
  34. data/lib/code/parser/code.rb +18 -0
  35. data/lib/code/parser/dictionnary.rb +41 -0
  36. data/lib/code/parser/list.rb +29 -0
  37. data/lib/code/parser/name.rb +49 -0
  38. data/lib/code/parser/nothing.rb +17 -0
  39. data/lib/code/parser/number.rb +98 -0
  40. data/lib/code/parser/statement.rb +11 -0
  41. data/lib/code/parser/string.rb +66 -0
  42. data/lib/code/parser.rb +4 -0
  43. data/lib/code.rb +27 -0
  44. data/lib/template/node/code_part.rb +13 -0
  45. data/lib/template/node/part.rb +19 -0
  46. data/lib/template/node/template.rb +13 -0
  47. data/lib/template/node/text_part.rb +13 -0
  48. data/lib/template/node.rb +4 -0
  49. data/lib/template/parser/template.rb +26 -0
  50. data/lib/template/parser.rb +4 -0
  51. data/lib/template-ruby.rb +6 -0
  52. data/lib/template.rb +20 -0
  53. data/spec/code/parser/boolean_spec.rb +18 -0
  54. data/spec/code/parser/call_spec.rb +39 -0
  55. data/spec/code/parser/dictionnary_spec.rb +46 -0
  56. data/spec/code/parser/list_spec.rb +29 -0
  57. data/spec/code/parser/name_spec.rb +15 -0
  58. data/spec/code/parser/nothing_spec.rb +19 -0
  59. data/spec/code/parser/number_spec.rb +117 -0
  60. data/spec/code/parser/string_spec.rb +29 -0
  61. data/spec/code_spec.rb +35 -0
  62. data/spec/spec_helper.rb +1 -0
  63. data/spec/template/parser/template_spec.rb +19 -0
  64. data/spec/template_spec.rb +30 -0
  65. data/template-ruby.gemspec +20 -0
  66. metadata +188 -0
@@ -0,0 +1,14 @@
1
+ class Code
2
+ class Parser
3
+ class Boolean < Parslet::Parser
4
+ rule(:nothing) { ::Code::Parser::Nothing.new }
5
+
6
+ rule(:true_keyword) { str("true") }
7
+ rule(:false_keyword) { str("false") }
8
+
9
+ rule(:boolean) { (true_keyword | false_keyword).as(:boolean) | nothing }
10
+
11
+ root(:boolean)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ class Code
2
+ class Parser
3
+ class Call < Parslet::Parser
4
+ rule(:dictionnary) { ::Code::Parser::Dictionnary.new }
5
+
6
+ rule(:dot) { str(".") }
7
+
8
+ rule(:call) do
9
+ (dictionnary.as(:left) >> dot >> call.as(:right)).as(:call) |
10
+ dictionnary
11
+ end
12
+
13
+ root(:call)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ class Code
2
+ class Parser
3
+ class Code < Parslet::Parser
4
+ rule(:statement) { ::Code::Parser::Statement.new }
5
+
6
+ rule(:space) { str(" ") }
7
+ rule(:newline) { str("\n") }
8
+ rule(:whitespace) { (space | newline).repeat(1) }
9
+ rule(:whitespace?) { whitespace.maybe }
10
+
11
+ rule(:code) do
12
+ (whitespace? >> statement >> whitespace?).repeat(1) | whitespace?
13
+ end
14
+
15
+ root(:code)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,41 @@
1
+ class Code
2
+ class Parser
3
+ class Dictionnary < Parslet::Parser
4
+ rule(:list) { ::Code::Parser::List.new }
5
+ rule(:code) { ::Code::Parser::Code.new }
6
+ rule(:string) { ::Code::Parser::String.new }
7
+
8
+ rule(:opening_curly_bracket) { str("{") }
9
+ rule(:closing_curly_bracket) { str("}") }
10
+ rule(:colon) { str(":") }
11
+ rule(:equal) { str("=") }
12
+ rule(:right_caret) { str(">") }
13
+ rule(:comma) { str(",") }
14
+
15
+ rule(:space) { str(" ") }
16
+ rule(:newline) { str("\n") }
17
+ rule(:whitespace) { (space | newline).repeat(1) }
18
+ rule(:whitespace?) { whitespace.maybe }
19
+
20
+ rule(:key_value) do
21
+ (string.as(:key) >> colon >> whitespace? >> code.as(:value)) |
22
+ (
23
+ code.as(:key) >> whitespace? >> equal >> right_caret >>
24
+ whitespace? >> code.as(:value)
25
+ )
26
+ end
27
+
28
+ rule(:dictionnary) do
29
+ (
30
+ opening_curly_bracket.ignore >> whitespace?.ignore >>
31
+ key_value.repeat(0, 1) >>
32
+ (whitespace? >> comma >> whitespace? >> key_value).repeat >>
33
+ whitespace?.ignore >> comma.maybe.ignore >> whitespace?.ignore >>
34
+ closing_curly_bracket.ignore
35
+ ).as(:dictionnary) | list
36
+ end
37
+
38
+ root(:dictionnary)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,29 @@
1
+ class Code
2
+ class Parser
3
+ class List < Parslet::Parser
4
+ rule(:string) { ::Code::Parser::String.new }
5
+ rule(:code) { ::Code::Parser::Code.new }
6
+
7
+ rule(:opening_square_bracket) { str("[") }
8
+ rule(:closing_square_bracket) { str("]") }
9
+ rule(:comma) { str(",") }
10
+
11
+ rule(:space) { str(" ") }
12
+ rule(:newline) { str("\n") }
13
+ rule(:whitespace) { (space | newline).repeat(1) }
14
+ rule(:whitespace?) { whitespace.maybe }
15
+
16
+ rule(:list) do
17
+ (
18
+ opening_square_bracket.ignore >> whitespace?.ignore >>
19
+ code.as(:code).repeat(0, 1) >>
20
+ (whitespace? >> comma >> whitespace? >> code.as(:code)).repeat >>
21
+ whitespace?.ignore >> comma.maybe.ignore >> whitespace?.ignore >>
22
+ closing_square_bracket.ignore
23
+ ).as(:list) | string
24
+ end
25
+
26
+ root(:list)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,49 @@
1
+ class Code
2
+ class Parser
3
+ class Name < Parslet::Parser
4
+ rule(:space) { str(" ") }
5
+ rule(:newline) { str("\n") }
6
+ rule(:comma) { str(",") }
7
+ rule(:colon) { str(":") }
8
+ rule(:dot) { str(".") }
9
+ rule(:single_quote) { str("'") }
10
+ rule(:double_quote) { str('"') }
11
+ rule(:opening_curly_bracket) { str("{") }
12
+ rule(:closing_curly_bracket) { str("}") }
13
+ rule(:opening_square_bracket) { str("[") }
14
+ rule(:closing_square_bracket) { str("]") }
15
+ rule(:equal) { str("=") }
16
+ rule(:left_caret) { str("<") }
17
+ rule(:right_caret) { str(">") }
18
+
19
+ rule(:zero) { str("0") }
20
+ rule(:one) { str("1") }
21
+ rule(:two) { str("2") }
22
+ rule(:three) { str("3") }
23
+ rule(:four) { str("4") }
24
+ rule(:five) { str("5") }
25
+ rule(:six) { str("6") }
26
+ rule(:seven) { str("7") }
27
+ rule(:eight) { str("8") }
28
+ rule(:nine) { str("9") }
29
+
30
+ rule(:digit) do
31
+ zero | one | two | three | four | five | six | seven | eight | nine
32
+ end
33
+
34
+ rule(:name_character) do
35
+ space.absent? >> newline.absent? >> comma.absent? >> colon.absent? >>
36
+ dot.absent? >> single_quote.absent? >> double_quote.absent? >>
37
+ opening_curly_bracket.absent? >> closing_curly_bracket.absent? >>
38
+ opening_square_bracket.absent? >> closing_square_bracket.absent? >>
39
+ equal.absent? >> left_caret.absent? >> right_caret.absent? >> any
40
+ end
41
+
42
+ rule(:name) do
43
+ (digit.absent? >> name_character >> name_character.repeat).as(:name)
44
+ end
45
+
46
+ root(:name)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,17 @@
1
+ class Code
2
+ class Parser
3
+ class Nothing < Parslet::Parser
4
+ rule(:name) { ::Code::Parser::Name.new }
5
+
6
+ rule(:nothing_keyword) { str("nothing") }
7
+ rule(:null_keyword) { str("null") }
8
+ rule(:nil_keyword) { str("nil") }
9
+
10
+ rule(:nothing) do
11
+ (nothing_keyword | null_keyword | nil_keyword).as(:nothing) | name
12
+ end
13
+
14
+ root(:nothing)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,98 @@
1
+ class Code
2
+ class Parser
3
+ class Number < Parslet::Parser
4
+ rule(:boolean) { ::Code::Parser::Boolean.new }
5
+
6
+ rule(:dot) { str(".") }
7
+ rule(:plus) { str("+") }
8
+ rule(:minus) { str("-") }
9
+
10
+ rule(:zero) { str("0") }
11
+ rule(:one) { str("1") }
12
+ rule(:two) { str("2") }
13
+ rule(:three) { str("3") }
14
+ rule(:four) { str("4") }
15
+ rule(:five) { str("5") }
16
+ rule(:six) { str("6") }
17
+ rule(:seven) { str("7") }
18
+ rule(:eight) { str("8") }
19
+ rule(:nine) { str("9") }
20
+ rule(:a) { str("a") | str("A") }
21
+ rule(:b) { str("b") | str("B") }
22
+ rule(:b) { str("b") | str("B") }
23
+ rule(:c) { str("c") | str("C") }
24
+ rule(:d) { str("d") | str("D") }
25
+ rule(:e) { str("e") | str("E") }
26
+ rule(:f) { str("f") | str("F") }
27
+ rule(:o) { str("o") | str("O") }
28
+ rule(:x) { str("x") | str("X") }
29
+
30
+ # sign
31
+
32
+ rule(:sign) { plus | minus }
33
+
34
+ # base 2
35
+
36
+ rule(:base_2_digit) { zero | one }
37
+
38
+ rule(:base_2_number) { zero.ignore >> b.ignore >> base_2_digit.repeat(1) }
39
+
40
+ # base 8
41
+
42
+ rule(:base_8_digit) do
43
+ zero | one | two | three | four | five | six | seven
44
+ end
45
+
46
+ rule(:base_8_number) { zero.ignore >> o.ignore >> base_8_digit.repeat(1) }
47
+
48
+ # base 10
49
+
50
+ rule(:base_10_digit) do
51
+ zero | one | two | three | four | five | six | seven | eight | nine
52
+ end
53
+
54
+ rule(:base_10_whole) { base_10_digit.repeat(1) }
55
+
56
+ rule(:base_10_exponent) { e.ignore >> base_10_number }
57
+
58
+ rule(:base_10_integer) do
59
+ sign.as(:sign).maybe >> base_10_whole.as(:whole) >>
60
+ base_10_exponent.as(:exponent).maybe
61
+ end
62
+
63
+ rule(:base_10_decimal_decimal) { dot.ignore >> base_10_digit.repeat(1) }
64
+
65
+ rule(:base_10_decimal) do
66
+ sign.as(:sign).maybe >> base_10_whole.as(:whole) >>
67
+ base_10_decimal_decimal.as(:decimal) >>
68
+ base_10_exponent.as(:exponent).maybe
69
+ end
70
+
71
+ rule(:base_10_number) do
72
+ base_10_decimal.as(:decimal) | base_10_integer.as(:integer)
73
+ end
74
+
75
+ # base 16
76
+
77
+ rule(:base_16_digit) do
78
+ zero | one | two | three | four | five | six | seven | eight | nine |
79
+ a | b | c | d | e | f
80
+ end
81
+
82
+ rule(:base_16_number) do
83
+ zero.ignore >> x.ignore >> base_16_digit.repeat(1)
84
+ end
85
+
86
+ # number
87
+
88
+ rule(:number) do
89
+ (
90
+ base_2_number.as(:base_2) | base_8_number.as(:base_8) |
91
+ base_16_number.as(:base_16) | base_10_number.as(:base_10)
92
+ ).as(:number) | boolean
93
+ end
94
+
95
+ root(:number)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,11 @@
1
+ class Code
2
+ class Parser
3
+ class Statement < Parslet::Parser
4
+ rule(:call) { ::Code::Parser::Call.new }
5
+
6
+ rule(:statement) { call }
7
+
8
+ root(:statement)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,66 @@
1
+ class Code
2
+ class Parser
3
+ class String < Parslet::Parser
4
+ rule(:number) { ::Code::Parser::Number.new }
5
+
6
+ rule(:single_quote) { str("'") }
7
+ rule(:double_quote) { str('"') }
8
+ rule(:backslash) { str("\\") }
9
+ rule(:zero) { str("0") }
10
+ rule(:one) { str("1") }
11
+ rule(:two) { str("2") }
12
+ rule(:three) { str("3") }
13
+ rule(:four) { str("4") }
14
+ rule(:five) { str("5") }
15
+ rule(:six) { str("6") }
16
+ rule(:seven) { str("7") }
17
+ rule(:eight) { str("8") }
18
+ rule(:nine) { str("9") }
19
+ rule(:a) { str("a") | str("A") }
20
+ rule(:b) { str("b") | str("B") }
21
+ rule(:b) { str("b") | str("B") }
22
+ rule(:c) { str("c") | str("C") }
23
+ rule(:d) { str("d") | str("D") }
24
+ rule(:e) { str("e") | str("E") }
25
+ rule(:f) { str("f") | str("F") }
26
+ rule(:n) { str("n") | str("N") }
27
+ rule(:r) { str("r") | str("R") }
28
+ rule(:t) { str("t") | str("T") }
29
+ rule(:u) { str("u") | str("U") }
30
+
31
+ rule(:base_16_digit) do
32
+ zero | one | two | three | four | five | six | seven | eight | nine |
33
+ a | b | c | d | e | f
34
+ end
35
+
36
+ rule(:escaped_character) do
37
+ (backslash >> u >> base_16_digit.repeat(4, 4)) |
38
+ (backslash >> (b | f | n | r | t)) | (backslash.ignore >> any)
39
+ end
40
+
41
+ rule(:single_quoted_character) do
42
+ escaped_character | (single_quote.absent? >> any)
43
+ end
44
+
45
+ rule(:double_quoted_character) do
46
+ escaped_character | (double_quote.absent? >> any)
47
+ end
48
+
49
+ rule(:single_quoted_string) do
50
+ single_quote.ignore >> single_quoted_character.repeat >>
51
+ single_quote.ignore
52
+ end
53
+
54
+ rule(:double_quoted_string) do
55
+ double_quote.ignore >> double_quoted_character.repeat >>
56
+ double_quote.ignore
57
+ end
58
+
59
+ rule(:string) do
60
+ (single_quoted_string | double_quoted_string).as(:string) | number
61
+ end
62
+
63
+ root(:string)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,4 @@
1
+ class Code
2
+ class Parser
3
+ end
4
+ end
data/lib/code.rb ADDED
@@ -0,0 +1,27 @@
1
+ require "active_support"
2
+ require "active_support/core_ext/object/blank"
3
+
4
+ class Code
5
+ def initialize(input)
6
+ @input = input
7
+ @parsed = ::Code::Parser::Code.new.parse(@input)
8
+ end
9
+
10
+ def self.evaluate(input, context = "")
11
+ new(input).evaluate(context)
12
+ end
13
+
14
+ def evaluate(context = "")
15
+ if context.present?
16
+ context = ::Code.evaluate(context)
17
+ else
18
+ context = ::Code::Object::Dictionnary.new
19
+ end
20
+
21
+ ::Code::Node::Code.new(parsed).evaluate(context)
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :input, :parsed
27
+ end
@@ -0,0 +1,13 @@
1
+ class Template
2
+ class Node
3
+ class CodePart
4
+ def initialize(code)
5
+ @code = ::Code::Node::Code.new(code)
6
+ end
7
+
8
+ def evaluate(context)
9
+ @code.evaluate(context)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ class Template
2
+ class Node
3
+ class Part
4
+ def initialize(part)
5
+ if part.key?(:text)
6
+ @part = ::Template::Node::TextPart.new(part[:text])
7
+ elsif part.key?(:code)
8
+ @part = ::Template::Node::CodePart.new(part[:code])
9
+ else
10
+ raise NotImplementedError.new(part.inspect)
11
+ end
12
+ end
13
+
14
+ def evaluate(context)
15
+ @part.evaluate(context)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ class Template
2
+ class Node
3
+ class Template
4
+ def initialize(parts)
5
+ @parts = parts.map { |part| ::Template::Node::Part.new(part) }
6
+ end
7
+
8
+ def evaluate(context)
9
+ ::Code::Object::List.new(@parts.map { |part| part.evaluate(context) })
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class Template
2
+ class Node
3
+ class TextPart
4
+ def initialize(text)
5
+ @text = text
6
+ end
7
+
8
+ def evaluate(_context)
9
+ ::Code::Object::String.new(@text.to_s)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ class Template
2
+ class Node
3
+ end
4
+ end
@@ -0,0 +1,26 @@
1
+ class Template
2
+ class Parser
3
+ class Template < Parslet::Parser
4
+ rule(:code) { ::Code::Parser::Code.new }
5
+
6
+ rule(:left_curly_bracket) { str("{") }
7
+ rule(:right_curly_bracket) { str("}") }
8
+ rule(:escape) { str("\\") }
9
+
10
+ rule(:text_part) do
11
+ (
12
+ (escape.ignore >> left_curly_bracket) |
13
+ (left_curly_bracket.absent? >> any)
14
+ ).repeat(1)
15
+ end
16
+
17
+ rule(:code_part) do
18
+ left_curly_bracket >> code >> (right_curly_bracket | any.absent?)
19
+ end
20
+
21
+ rule(:template) { (text_part.as(:text) | code_part.as(:code)).repeat(1) }
22
+
23
+ root(:template)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ class Template
2
+ class Parser
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ require "parslet"
2
+ require "zeitwerk"
3
+
4
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
5
+ loader.ignore(__FILE__)
6
+ loader.setup
data/lib/template.rb ADDED
@@ -0,0 +1,20 @@
1
+ class Template
2
+ def initialize(input)
3
+ @input = input
4
+ @parsed = ::Template::Parser::Template.new.parse(@input)
5
+ end
6
+
7
+ def self.render(input, context = "")
8
+ new(input).render(context)
9
+ end
10
+
11
+ def render(context = "")
12
+ if context.present?
13
+ context = ::Code.evaluate(context)
14
+ else
15
+ context = ::Code::Object::Dictionnary.new
16
+ end
17
+
18
+ ::Template::Node::Template.new(@parsed).evaluate(context).map(&:to_s).join
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Boolean do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ ["true", { boolean: "true" }],
8
+ ["false", { boolean: "false" }]
9
+ ].each do |(input, expected)|
10
+ context input.inspect do
11
+ let(:input) { input }
12
+
13
+ it "succeeds" do
14
+ expect(subject).to eq(expected)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Call do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ [
8
+ "user.first_name",
9
+ { call: { left: { name: "user" }, right: { name: "first_name" } } }
10
+ ],
11
+ [
12
+ "3.times",
13
+ {
14
+ call: {
15
+ left: {
16
+ number: {
17
+ base_10: {
18
+ integer: {
19
+ whole: "3"
20
+ }
21
+ }
22
+ }
23
+ },
24
+ right: {
25
+ name: "times"
26
+ }
27
+ }
28
+ }
29
+ ]
30
+ ].each do |(input, expected)|
31
+ context input.inspect do
32
+ let(:input) { input }
33
+
34
+ it "succeeds" do
35
+ expect(subject).to eq(expected)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Dictionnary do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ [
8
+ '{name: "Dorian"}',
9
+ {
10
+ dictionnary: [{ key: { name: "name" }, value: [{ string: "Dorian" }] }]
11
+ }
12
+ ],
13
+ [
14
+ '{a: true, "b": false}',
15
+ {
16
+ dictionnary: [
17
+ { key: { name: "a" }, value: [{ boolean: "true" }] },
18
+ { key: { string: "b" }, value: [{ boolean: "false" }] }
19
+ ]
20
+ }
21
+ ],
22
+ [
23
+ "{ true => 1, false => 2}",
24
+ {
25
+ dictionnary: [
26
+ {
27
+ key: [{ boolean: "true" }],
28
+ value: [{ number: { base_10: { integer: { whole: "1" } } } }]
29
+ },
30
+ {
31
+ key: [{ boolean: "false" }],
32
+ value: [{ number: { base_10: { integer: { whole: "2" } } } }]
33
+ }
34
+ ]
35
+ }
36
+ ]
37
+ ].each do |(input, expected)|
38
+ context input.inspect do
39
+ let(:input) { input }
40
+
41
+ it "succeeds" do
42
+ expect(subject).to eq(expected)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::List do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ [
8
+ "[true, false]",
9
+ {
10
+ list: [
11
+ { code: [{ boolean: "true" }] },
12
+ { code: [{ boolean: "false" }] }
13
+ ]
14
+ }
15
+ ],
16
+ [
17
+ "[nothing, a]",
18
+ { list: [{ code: [{ nothing: "nothing" }] }, { code: [{ name: "a" }] }] }
19
+ ]
20
+ ].each do |(input, expected)|
21
+ context input.inspect do
22
+ let(:input) { input }
23
+
24
+ it "succeeds" do
25
+ expect(subject).to eq(expected)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Name do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ %w[user dorian User RSpec describe?].each do |(input, expected)|
7
+ context input.inspect do
8
+ let(:input) { input }
9
+
10
+ it "succeeds" do
11
+ expect(subject).to eq({ name: input })
12
+ end
13
+ end
14
+ end
15
+ end