template-ruby 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 (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