liquidscript 0.0.1

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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +11 -0
  6. data/Guardfile +9 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +59 -0
  9. data/Rakefile +25 -0
  10. data/lib/liquidscript.rb +11 -0
  11. data/lib/liquidscript/buffer.rb +34 -0
  12. data/lib/liquidscript/compiler.rb +9 -0
  13. data/lib/liquidscript/compiler/base.rb +101 -0
  14. data/lib/liquidscript/compiler/base/action.rb +39 -0
  15. data/lib/liquidscript/compiler/base/blank.rb +24 -0
  16. data/lib/liquidscript/compiler/base/callable.rb +51 -0
  17. data/lib/liquidscript/compiler/base/helpers.rb +207 -0
  18. data/lib/liquidscript/compiler/icr.rb +40 -0
  19. data/lib/liquidscript/compiler/icr/classes.rb +59 -0
  20. data/lib/liquidscript/compiler/icr/expressions.rb +94 -0
  21. data/lib/liquidscript/compiler/icr/functions.rb +42 -0
  22. data/lib/liquidscript/compiler/icr/helpers.rb +20 -0
  23. data/lib/liquidscript/compiler/icr/literals.rb +106 -0
  24. data/lib/liquidscript/errors.rb +51 -0
  25. data/lib/liquidscript/generator.rb +11 -0
  26. data/lib/liquidscript/generator/base.rb +25 -0
  27. data/lib/liquidscript/generator/base/dsl.rb +19 -0
  28. data/lib/liquidscript/generator/base/replacements.rb +33 -0
  29. data/lib/liquidscript/generator/context.rb +7 -0
  30. data/lib/liquidscript/generator/javascript.rb +37 -0
  31. data/lib/liquidscript/generator/javascript/literals.rb +63 -0
  32. data/lib/liquidscript/generator/javascript/metas.rb +41 -0
  33. data/lib/liquidscript/generator/javascript/objects.rb +137 -0
  34. data/lib/liquidscript/icr.rb +18 -0
  35. data/lib/liquidscript/icr/code.rb +68 -0
  36. data/lib/liquidscript/icr/context.rb +94 -0
  37. data/lib/liquidscript/icr/representable.rb +39 -0
  38. data/lib/liquidscript/icr/set.rb +147 -0
  39. data/lib/liquidscript/icr/sexp.rb +41 -0
  40. data/lib/liquidscript/icr/variable.rb +68 -0
  41. data/lib/liquidscript/scanner.rb +40 -0
  42. data/lib/liquidscript/scanner/lexer.rl +106 -0
  43. data/lib/liquidscript/scanner/token.rb +37 -0
  44. data/lib/liquidscript/template.rb +16 -0
  45. data/lib/liquidscript/version.rb +5 -0
  46. data/liquidscript.gemspec +27 -0
  47. data/spec/fixtures/class.compile.yml +26 -0
  48. data/spec/fixtures/class.generate.yml +31 -0
  49. data/spec/fixtures/combination.generate.yml +33 -0
  50. data/spec/fixtures/complex.generate.yml +20 -0
  51. data/spec/fixtures/expression.generate.yml +4 -0
  52. data/spec/fixtures/function.generate.yml +11 -0
  53. data/spec/fixtures/get.generate.yml +5 -0
  54. data/spec/fixtures/literals.generate.yml +8 -0
  55. data/spec/fixtures/main.compile.yml +32 -0
  56. data/spec/fixtures/set.generate.yml +4 -0
  57. data/spec/fixtures/string.generate.yml +6 -0
  58. data/spec/lib/liquidscript/buffer_spec.rb +14 -0
  59. data/spec/lib/liquidscript/compiler/icr_spec.rb +139 -0
  60. data/spec/lib/liquidscript/generator/javascript_spec.rb +15 -0
  61. data/spec/lib/liquidscript/icr/code_spec.rb +0 -0
  62. data/spec/lib/liquidscript/icr/context_spec.rb +36 -0
  63. data/spec/lib/liquidscript/icr/set_spec.rb +59 -0
  64. data/spec/lib/liquidscript/scanner/lexer_spec.rb +58 -0
  65. data/spec/lib/liquidscript/scanner/token_spec.rb +0 -0
  66. data/spec/lib/liquidscript/scanner_spec.rb +21 -0
  67. data/spec/spec_helper.rb +30 -0
  68. data/spec/support/helpers/lexer_helper.rb +5 -0
  69. data/spec/support/matchers/be_token.rb +9 -0
  70. data/spec/support/matchers/compile.rb +41 -0
  71. data/spec/support/matchers/generate.rb +46 -0
  72. metadata +210 -0
@@ -0,0 +1,139 @@
1
+ require "spec_helper"
2
+ require "yaml"
3
+
4
+ describe Compiler::ICR do
5
+
6
+ let(:scanner) do
7
+ iterator = double("iterator")
8
+ scanner = double("scanner")
9
+
10
+ expect(scanner).to receive(:each).once.and_return(iterator)
11
+ allow(iterator).to receive(:next).and_return([
12
+ Scanner::Token.new(:number, "32", 0, 0),
13
+ Scanner::Token.new(:number, "10", 0, 0)])
14
+ allow(iterator).to receive(:peek).and_return(
15
+ Scanner::Token.new(:number, "32", 0, 0))
16
+ allow(iterator).to receive(:rewind)
17
+ scanner
18
+ end
19
+
20
+ subject do
21
+ described_class.new(scanner)
22
+ end
23
+
24
+ describe "#peek" do
25
+ specify { expect(subject.peek).to be_a Scanner::Token }
26
+ specify { expect(subject.peek).to be_type :number }
27
+ end
28
+
29
+ describe "#expect" do
30
+
31
+ context "with one argument" do
32
+ before do
33
+ expect(subject).to receive(:compile_number).once
34
+ end
35
+
36
+ it "calls the corresponding method" do
37
+ subject.expect :number
38
+ end
39
+ end
40
+
41
+ context "with a mismatching argument" do
42
+ it "raises an error" do
43
+ expect {
44
+ subject.expect :string
45
+ }.to raise_error CompileError
46
+ end
47
+ end
48
+
49
+ context "with a hash argument" do
50
+ let :probe do
51
+ block = lambda {}
52
+
53
+ expect(block).to receive(:arity).once.and_return(0)
54
+ expect(block).to receive(:call).once.with(no_args)
55
+ block
56
+ end
57
+
58
+ let :bad_probe do
59
+ block = lambda {}
60
+
61
+ expect(block).to_not receive(:arity)
62
+ expect(block).to_not receive(:call)
63
+ end
64
+
65
+ context "and a symbol value" do
66
+ before do
67
+ expect(subject).to receive(:compile_something).once
68
+ end
69
+
70
+ it "calls the corresponding method" do
71
+ subject.expect :number => :something
72
+ end
73
+ end
74
+
75
+ context "and a block value" do
76
+
77
+ it "calls the corresponding block" do
78
+ subject.expect :number => probe
79
+ end
80
+ end
81
+
82
+ context "with no right action" do
83
+ it "raises an error" do
84
+ expect {
85
+ subject.expect :string => :foo
86
+ }.to raise_error CompileError
87
+ end
88
+
89
+ it "uses the catch all" do
90
+ subject.expect :string => bad_probe,
91
+ :_ => probe
92
+ end
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ describe "#compile" do
99
+ specify {
100
+ expect("hello = 3").to compile.and_produce([:exec,
101
+ [:_context, [:hello]], [:set, [:_variable, :hello], [:number, "3"]]
102
+ ])
103
+ }
104
+
105
+ specify {
106
+ expect("{hello: 'world}").to compile.and_produce([:exec,
107
+ [:_context, []], [:object, [[[:identifier, "hello"], [:sstring, "world"]]]]
108
+ ])
109
+ }
110
+
111
+ specify {
112
+ expect("(test)-> { 2 }").to compile.and_produce([:exec,
113
+ [:_context, []], [:function,
114
+ [:exec,
115
+ [:_context, [:test]],
116
+ [:_arguments, [[:identifier, "test"]]],
117
+ [:number, "2"]
118
+ ]
119
+ ]])
120
+ }
121
+
122
+ specify { expect("(2)").to compile }
123
+ specify { expect("(2)->").to_not compile }
124
+ specify { expect("()-> {}").to compile }
125
+ specify { expect("(test)-> {}").to compile }
126
+ specify { expect("(test, foo)-> {}").to compile }
127
+ end
128
+
129
+ describe "with fixtures" do
130
+ Dir.glob("spec/fixtures/*.compile.yml") do |file|
131
+ content = YAML.load_file file
132
+ file =~ /spec\/fixtures\/(.*)\.compile\.yml/
133
+
134
+ it "compiles #{$1}" do
135
+ expect(content["data"]).to compile.and_produce content["compiled"]
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+ require "yaml"
3
+
4
+ describe Liquidscript::Generator::Javascript do
5
+ describe "with fixtures" do
6
+ Dir.glob("spec/fixtures/*.generate.yml") do |file|
7
+ content = YAML.load_file file
8
+ file =~ /spec\/fixtures\/(.*)\.generate\.yml/
9
+
10
+ it "generates #{$1}" do
11
+ expect(content["data"]).to generate(content["compiled"])
12
+ end
13
+ end
14
+ end
15
+ end
File without changes
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+
3
+ include Liquidscript
4
+
5
+ describe ICR::Context do
6
+
7
+ it "creates a variable" do
8
+ expect(subject.set(:test)).to be_a ICR::Variable
9
+ end
10
+
11
+ it "gives an invalid reference" do
12
+ expect {
13
+ subject.get(:test)
14
+ }.to raise_error Liquidscript::InvalidReferenceError
15
+ end
16
+
17
+ context "with a parent" do
18
+
19
+ let(:parent) do
20
+ parent = double("parent")
21
+ expect(parent).to receive(:get).once.with(:foo).and_return(:test)
22
+ parent
23
+ end
24
+
25
+ subject do
26
+ context = ICR::Context.new
27
+ context.parent = parent
28
+ context
29
+ end
30
+
31
+ it "retrives the variable" do
32
+ expect(subject.get(:foo)).to be :test
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,59 @@
1
+ require "spec_helper"
2
+
3
+ include Liquidscript
4
+
5
+ describe ICR::Set do
6
+
7
+ its(:metadata) { should be_a Hash }
8
+
9
+ describe "#to_a" do
10
+ specify { expect(subject.to_a).to be_an Array }
11
+ specify { expect(subject.to_a).to have(1).item }
12
+
13
+ context "with metadata" do
14
+ subject do
15
+ set = ICR::Set.new
16
+ set.metadata.merge! :hello => "world"
17
+ set
18
+ end
19
+
20
+ specify { expect(subject.to_a).to have(2).items }
21
+ specify { expect(subject.to_a).to eq [:exec, [:_hello, "world"]] }
22
+
23
+ end
24
+
25
+ context "with codes" do
26
+ subject do
27
+ set = ICR::Set.new
28
+ set << "test"
29
+ set
30
+ end
31
+
32
+ specify { expect(subject.to_a).to have(2).item }
33
+ specify { expect(subject.to_a).to eq [:exec, "test"] }
34
+
35
+ end
36
+
37
+ context "with both" do
38
+ subject do
39
+ set = ICR::Set.new
40
+ set.metadata.merge! :hello => "world"
41
+ set << "test"
42
+ set
43
+ end
44
+
45
+ specify { expect(subject.to_a).to have(3).items }
46
+ specify { expect(subject.to_a).to eq [:exec, [:_hello, "world"], "test"] }
47
+
48
+ end
49
+ end
50
+
51
+ describe "#add" do
52
+ it "adds a code to the set" do
53
+ subject.add(:number, "32")
54
+
55
+ expect(subject.to_a).to have(2).items
56
+ expect(subject.to_a.last).to be_a ICR::Code
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ describe Liquidscript::Scanner::Lexer, :lexer_helper do
4
+ subject { described_class.new }
5
+ describe "#emit" do
6
+ it "pushes a token" do
7
+ subject.instance_exec { @data = "hello"; @ts = 0; @te = 6 }
8
+ subject.emit(:test)
9
+ expect(subject.tokens.first).to be_token(:test, "hello")
10
+ end
11
+ end
12
+
13
+ describe "#perform" do
14
+ it "scans a number" do
15
+ expect(scan("43")).to eq [
16
+ [:number, "43"]
17
+ ]
18
+ end
19
+
20
+ it "scans a string" do
21
+ scan('"hello world" ').should eq [
22
+ [:dstring, '"hello world"']
23
+ ]
24
+
25
+ scan(" 'foobar").should eq [
26
+ [:sstring, "'foobar"]
27
+ ]
28
+ end
29
+
30
+ it "scans an identifier" do
31
+ scan('test = 4').should eq [
32
+ [:identifier, "test"],
33
+ [:equal, "="],
34
+ [:number, "4"]
35
+ ]
36
+ end
37
+
38
+ it "scans brackets" do
39
+ scan("{ test = 3 }").should eq [
40
+ [:lbrack, "{"],
41
+ [:identifier, "test"],
42
+ [:equal, "="],
43
+ [:number, "3"],
44
+ [:rbrack, "}"]
45
+ ]
46
+ end
47
+
48
+ it "scans keywords" do
49
+ scan("return test = new foo").should eq [
50
+ [:keyword, "return"],
51
+ [:identifier, "test"],
52
+ [:equal, "="],
53
+ [:keyword, "new"],
54
+ [:identifier, "foo"]
55
+ ]
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe Liquidscript::Scanner do
4
+ subject { described_class.new("42") }
5
+ it { should be_a Enumerable }
6
+
7
+ describe "#each" do
8
+ specify { expect(subject.each).to be_a Enumerator }
9
+ specify { expect { |y| subject.each(&y) }.to yield_control.once }
10
+ end
11
+
12
+ context "with invalid input" do
13
+ subject { described_class.new("'test'") }
14
+
15
+ it "raises an error" do
16
+ expect {
17
+ subject.each
18
+ }.to raise_error Liquidscript::SyntaxError
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ require "bundler/setup"
2
+ Bundler.setup
3
+
4
+ require "coveralls"
5
+ Coveralls.wear!
6
+
7
+ require "liquidscript"
8
+
9
+ include Liquidscript
10
+
11
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
12
+
13
+ # This file was generated by the `rspec --init` command. Conventionally, all
14
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
15
+ # Require this file using `require "spec_helper"` to ensure that it is only
16
+ # loaded once.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+ RSpec.configure do |config|
20
+ config.treat_symbols_as_metadata_keys_with_true_values = true
21
+ config.run_all_when_everything_filtered = true
22
+
23
+ # Run specs in random order to surface order dependencies. If you find an
24
+ # order dependency and want to debug it, you can fix the order by providing
25
+ # the seed, which is printed after each run.
26
+ # --seed 1234
27
+ config.order = 'random'
28
+
29
+ config.include LexerHelper, :lexer_helper
30
+ end
@@ -0,0 +1,5 @@
1
+ module LexerHelper
2
+ def scan(source)
3
+ subject.perform(source)
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ RSpec::Matchers.define :be_token do |type, value|
2
+ match do |data|
3
+ data == Liquidscript::Scanner::Token.new(type, value, 0, 0)
4
+ end
5
+
6
+ description do
7
+ "be token #{[type, value].inspect}"
8
+ end
9
+ end
@@ -0,0 +1,41 @@
1
+ RSpec::Matchers.define :compile do
2
+ include Liquidscript
3
+
4
+ chain :and_produce do |prod|
5
+ @prod = prod
6
+ end
7
+
8
+ match do |data|
9
+ if @prod
10
+ (@_out = compiler(data).compile) == @prod
11
+ else
12
+ @_out = compiler(data).compile?
13
+ end
14
+ end
15
+
16
+ failure_message_for_should do |data|
17
+ "expected #{data} to compile correctly"
18
+ end
19
+
20
+ failure_message_for_should_not do |data|
21
+ "expected #{data} not to compile (compiled anyway, got: #{@_out})"
22
+ end
23
+
24
+ description do |data|
25
+ "compile #{data}"
26
+ end
27
+
28
+ diffable
29
+
30
+ def expected
31
+ @prod
32
+ end
33
+
34
+ def actual
35
+ @_out || []
36
+ end
37
+
38
+ def compiler(data)
39
+ Compiler::ICR.new(Scanner.new(data))
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ RSpec::Matchers.define :generate do |v|
2
+ include Liquidscript
3
+
4
+ match do |data|
5
+ (@_out = for_match(generator(data).generate)) ==
6
+ (@_expected = for_match(v))
7
+ end
8
+
9
+ description do |data|
10
+ "generate #{v}"
11
+ end
12
+
13
+ failure_message_for_should do |data|
14
+ sprintf "expected %{source} to generate %{dest} (got: %{actual}) - %{tree}",
15
+ :source => data.inspect,
16
+ :dest => for_match(v).inspect,
17
+ :actual => actual.inspect,
18
+ :tree => tree(data)
19
+ end
20
+
21
+ def actual
22
+ @_out
23
+ end
24
+
25
+ def expected
26
+ @_expected
27
+ end
28
+
29
+ diffable
30
+
31
+ def generator(data)
32
+ compiler = Compiler::ICR.new(Scanner.new(data))
33
+ compiler.compile
34
+ Generator::Javascript.new(compiler.top)
35
+ end
36
+
37
+ def tree(data)
38
+ compiler = Compiler::ICR.new(Scanner.new(data))
39
+ compiler.compile
40
+ compiler.top.to_sexp
41
+ end
42
+
43
+ def for_match(str)
44
+ str.to_s.gsub(/[\s\n\t]+/, '')
45
+ end
46
+ end