scribble 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +455 -0
  6. data/Rakefile +2 -0
  7. data/lib/scribble.rb +44 -0
  8. data/lib/scribble/block.rb +25 -0
  9. data/lib/scribble/converter.rb +10 -0
  10. data/lib/scribble/errors.rb +24 -0
  11. data/lib/scribble/method.rb +91 -0
  12. data/lib/scribble/methods/if.rb +26 -0
  13. data/lib/scribble/methods/layout.rb +25 -0
  14. data/lib/scribble/methods/partial.rb +14 -0
  15. data/lib/scribble/methods/times.rb +11 -0
  16. data/lib/scribble/nodes/call.rb +55 -0
  17. data/lib/scribble/nodes/ending.rb +6 -0
  18. data/lib/scribble/nodes/node.rb +24 -0
  19. data/lib/scribble/nodes/value.rb +16 -0
  20. data/lib/scribble/objects/boolean.rb +33 -0
  21. data/lib/scribble/objects/fixnum.rb +53 -0
  22. data/lib/scribble/objects/nil.rb +21 -0
  23. data/lib/scribble/objects/string.rb +62 -0
  24. data/lib/scribble/parsing/nester.rb +49 -0
  25. data/lib/scribble/parsing/parser.rb +132 -0
  26. data/lib/scribble/parsing/reporter.rb +71 -0
  27. data/lib/scribble/parsing/transform.rb +87 -0
  28. data/lib/scribble/partial.rb +41 -0
  29. data/lib/scribble/registry.rb +95 -0
  30. data/lib/scribble/support/context.rb +98 -0
  31. data/lib/scribble/support/matcher.rb +74 -0
  32. data/lib/scribble/support/unmatched.rb +70 -0
  33. data/lib/scribble/support/utilities.rb +49 -0
  34. data/lib/scribble/template.rb +61 -0
  35. data/lib/scribble/version.rb +3 -0
  36. data/scribble.gemspec +22 -0
  37. data/test/all.rb +23 -0
  38. data/test/errors_test.rb +94 -0
  39. data/test/methods/if_test.rb +49 -0
  40. data/test/methods/layout_test.rb +71 -0
  41. data/test/methods/partial_test.rb +85 -0
  42. data/test/methods/times_test.rb +10 -0
  43. data/test/objects/boolean_test.rb +162 -0
  44. data/test/objects/fixnum_test.rb +236 -0
  45. data/test/objects/nil_test.rb +83 -0
  46. data/test/objects/string_test.rb +268 -0
  47. data/test/parsing/parsing_test.rb +234 -0
  48. data/test/registry_test.rb +264 -0
  49. data/test/template_test.rb +51 -0
  50. data/test/test_helper.rb +65 -0
  51. metadata +127 -0
@@ -0,0 +1,3 @@
1
+ module Scribble
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'scribble/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "scribble"
8
+ spec.version = Scribble::VERSION
9
+ spec.authors = ["Stefan Kroes"]
10
+ spec.email = ["stefan.kroes@lab01.nl"]
11
+ spec.summary = "Scribble is a client facing template language similar to Liquid build in Ruby"
12
+ spec.description = "Scribble is a client facing template language similar to Liquid. Scribble was written in Ruby and can be used in any Ruby or Ruby on Rails project. It takes a template file, consisting of text and Scribble tags and transforms it into text. Scribble can be used to transform any plain text format like HTML, Markdown, JSON, XML, etc. Client facing means that it is safe to use Scribble to run/evaluate user provided templates."
13
+ spec.homepage = "https://github.com/stefankroes/scribble"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "parslet", "~> 1.6"
22
+ end
@@ -0,0 +1,23 @@
1
+ # Parsing
2
+
3
+ require_relative 'parsing/parsing_test'
4
+
5
+ # Main components
6
+
7
+ require_relative 'registry_test'
8
+ require_relative 'template_test'
9
+ require_relative 'errors_test'
10
+
11
+ # Object registrations
12
+
13
+ require_relative 'objects/boolean_test'
14
+ require_relative 'objects/fixnum_test'
15
+ require_relative 'objects/nil_test'
16
+ require_relative 'objects/string_test'
17
+
18
+ # Method registrations
19
+
20
+ require_relative 'methods/if_test'
21
+ require_relative 'methods/layout_test'
22
+ require_relative 'methods/partial_test'
23
+ require_relative 'methods/times_test'
@@ -0,0 +1,94 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe Scribble do
4
+ it 'provides syntax errors' do
5
+ assert_scribble_raises '{{ + 1 }}', Scribble::Errors::Syntax, "Unexpected '+' at line 1 column 4, expected '(', 'end', '}}' or a value"
6
+ assert_scribble_raises '{{ 1 + }}', Scribble::Errors::Syntax, "Unexpected '}' at line 1 column 8, expected '(' or a value"
7
+ assert_scribble_raises '{{ 1 + ( ) }}', Scribble::Errors::Syntax, "Unexpected ')' at line 1 column 10, expected '(' or a value"
8
+ assert_scribble_raises '{{ if', Scribble::Errors::Syntax, "Unexpected end of template at line 1 column 6, expected '(', '}}' or an operator"
9
+ assert_scribble_raises '{{ if {{', Scribble::Errors::Syntax, "Unexpected '{' at line 1 column 7, expected '(', '}}', a value or an operator"
10
+ assert_scribble_raises '{{ \' }} ', Scribble::Errors::Syntax, "Unexpected end of template at line 1 column 9; unterminated string"
11
+ end
12
+
13
+ it 'provides syntax errors for inproper block nesting' do
14
+ assert_scribble_raises '{{ if }}', Scribble::Errors::Syntax, "Unexpected end of template; unclosed 'if' block at line 1 column 4"
15
+ assert_scribble_raises '{{ end }}', Scribble::Errors::Syntax, "Unexpected 'end' at line 1 column 4; no block currently open"
16
+ end
17
+
18
+ it 'provides syntax errors for unexpected split methods' do
19
+ assert_scribble_raises '{{ if false }}{{ else }}{{ else }}{{ end }}', Scribble::Errors::Syntax, "Unexpected 'else' at line 1 column 28"
20
+ end
21
+
22
+ it 'provides syntax errors for unexpected block methods' do
23
+ assert_scribble_raises '{{ if if false }}{{ end }}', Scribble::Errors::Syntax, "Unexpected 'if' at line 1 column 7; block methods can't be arguments"
24
+ end
25
+
26
+ it 'provides undefined errors' do
27
+ assert_scribble_raises '{{ foo }}', Scribble::Errors::Undefined, "Undefined variable or method 'foo' at line 1 column 4"
28
+ assert_scribble_raises '{{ partial foo }}', Scribble::Errors::Undefined, "Undefined variable or method 'foo' at line 1 column 12"
29
+ assert_scribble_raises '{{ foo() }}', Scribble::Errors::Undefined, "Undefined method 'foo' at line 1 column 4"
30
+ assert_scribble_raises '{{ foo 1 }}', Scribble::Errors::Undefined, "Undefined method 'foo' at line 1 column 4"
31
+ end
32
+
33
+ it 'provides arity errors' do
34
+ Scribble::Registry.reset do
35
+ Scribble::Registry.for Fixnum do
36
+ method :qux
37
+ method :qux, Fixnum, String, [String, 1]
38
+ method :qux, Fixnum, String, String, String, String, [Fixnum]
39
+ end
40
+
41
+ assert_scribble_raises '{{ partial }}', Scribble::Errors::Arity, "Wrong number of arguments (0 for 1-2) for 'partial' at line 1 column 4"
42
+ assert_scribble_raises '{{ 0.add }}', Scribble::Errors::Arity, "Wrong number of arguments (0 for 1) for 'add' at line 1 column 6"
43
+ assert_scribble_raises '{{ 0.qux 0 }}', Scribble::Errors::Arity, "Wrong number of arguments (1 for 0, 2-3 or 5+) for 'qux' at line 1 column 6"
44
+ end
45
+ end
46
+
47
+ it 'provides argument errors' do
48
+ Scribble::Registry.reset do
49
+ Scribble::Registry.for Fixnum do
50
+ method :qux, [Fixnum], String
51
+ end
52
+
53
+ assert_scribble_raises '{{ partial 1 }}', Scribble::Errors::Argument, "Expected string as 1st argument to 'partial', got number at line 1 column 12"
54
+ assert_scribble_raises '{{ 0.qux 1 }}', Scribble::Errors::Argument, "Expected string as 2nd argument to 'qux' at line 1 column 6"
55
+ assert_scribble_raises "{{ 0.qux '', 1 }}", Scribble::Errors::Argument, "Unexpected 2nd argument to 'qux', got number at line 1 column 14"
56
+ end
57
+ end
58
+
59
+ it 'provides specific argument errors with locations' do
60
+ assert_scribble_raises "{{ '' * -1 }}", Scribble::Errors::Argument, "Can't repeat string a negative number of times at line 1 column 7"
61
+ assert_scribble_raises "{{ ''.truncate(-1) }}", Scribble::Errors::Argument, "Can't truncate string with a negative length at line 1 column 7"
62
+ assert_scribble_raises "{{ 1 / 0 }}", Scribble::Errors::Argument, 'Division by zero at line 1 column 6'
63
+ end
64
+
65
+ it 'combines errors generated in nested contexts' do
66
+ Scribble::Registry.reset do
67
+ class SomeBlock < Scribble::Block
68
+ def foo; render; end; register :foo
69
+ method :bar, Fixnum, returns: 'bar'
70
+ method :baz, Fixnum, [Fixnum], returns: 'baz'
71
+ end
72
+
73
+ class SomeMethod < Scribble::Method
74
+ def baz string; 'baz'; end; register :baz, String
75
+ end
76
+
77
+ assert_scribble_raises '{{ foo }}{{ bar }}{{ end }}', Scribble::Errors::Arity, "Wrong number of arguments (0 for 1) for 'bar' at line 1 column 13"
78
+ assert_scribble_raises '{{ foo }}{{ baz }}{{ end }}', Scribble::Errors::Arity, "Wrong number of arguments (0 for 1 or 1+) for 'baz' at line 1 column 13"
79
+ assert_scribble_raises '{{ foo }}{{ baz true }}{{ end }}', Scribble::Errors::Argument, "Expected string or number as 1st argument to 'baz', got boolean at line 1 column 17"
80
+ end
81
+ end
82
+
83
+ it 'does not call split methods from a nested context' do
84
+ Scribble::Registry.reset do
85
+ class SomeBlock < Scribble::Block
86
+ register :foo
87
+ def foo; render; end
88
+ method :bar, split: true
89
+ end
90
+
91
+ assert_scribble_raises '{{ foo }}{{ if true }}{{ bar }}{{ end }}{{ end }}', Scribble::Errors::Undefined, "Undefined variable or method 'bar' at line 1 column 26"
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,49 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe Scribble::Methods::If do
4
+ it 'renders according if-elsif-else semantics' do
5
+ assert_scribble_render '{{ if true }}Foo {{ end }}Bar', 'Foo Bar'
6
+ assert_scribble_render '{{ if false }}Foo {{ end }}Bar', 'Bar'
7
+
8
+ assert_scribble_render '{{ if true }}Foo {{ else }}Bar {{ end }}Baz', 'Foo Baz'
9
+ assert_scribble_render '{{ if false }}Foo {{ else }}Bar {{ end }}Baz', 'Bar Baz'
10
+
11
+ assert_scribble_render '{{ if true }}Foo {{ elsif true }}Bar {{ end }}Baz', 'Foo Baz'
12
+ assert_scribble_render '{{ if false }}Foo {{ elsif true }}Bar {{ end }}Baz', 'Bar Baz'
13
+ assert_scribble_render '{{ if true }}Foo {{ elsif false }}Bar {{ end }}Baz', 'Foo Baz'
14
+ assert_scribble_render '{{ if false }}Foo {{ elsif false }}Bar {{ end }}Baz', 'Baz'
15
+
16
+ assert_scribble_render '{{ if true }}Foo {{ elsif true }}Bar {{ else }}Qux {{ end }}Baz', 'Foo Baz'
17
+ assert_scribble_render '{{ if false }}Foo {{ elsif true }}Bar {{ else }}Qux {{ end }}Baz', 'Bar Baz'
18
+ assert_scribble_render '{{ if true }}Foo {{ elsif false }}Bar {{ else }}Qux {{ end }}Baz', 'Foo Baz'
19
+ assert_scribble_render '{{ if false }}Foo {{ elsif false }}Bar {{ else }}Qux {{ end }}Baz', 'Qux Baz'
20
+ end
21
+
22
+ it 'casts numbers to booleans' do
23
+ assert_scribble_render '{{ if 1 }}Foo {{ elsif 1 }}Bar {{ end }}Baz', 'Foo Baz'
24
+ assert_scribble_render '{{ if 0 }}Foo {{ elsif 1 }}Bar {{ end }}Baz', 'Bar Baz'
25
+ assert_scribble_render '{{ if 1 }}Foo {{ elsif 0 }}Bar {{ end }}Baz', 'Foo Baz'
26
+ assert_scribble_render '{{ if 0 }}Foo {{ elsif 0 }}Bar {{ end }}Baz', 'Baz'
27
+ end
28
+
29
+ it 'casts strings to booleans' do
30
+ assert_scribble_render '{{ if 1 }}Foo {{ elsif 1 }}Bar {{ end }}Baz', 'Foo Baz'
31
+ assert_scribble_render '{{ if 0 }}Foo {{ elsif 1 }}Bar {{ end }}Baz', 'Bar Baz'
32
+ assert_scribble_render '{{ if 1 }}Foo {{ elsif 0 }}Bar {{ end }}Baz', 'Foo Baz'
33
+ assert_scribble_render '{{ if 0 }}Foo {{ elsif 0 }}Bar {{ end }}Baz', 'Baz'
34
+ end
35
+
36
+ it 'works with boolean expressions' do
37
+ assert_scribble_render '{{ if 1 = 1 }}Foo {{ elsif 1 < 2 }}Bar {{ end }}Baz', 'Foo Baz'
38
+ assert_scribble_render '{{ if 3 > 10 }}Foo {{ elsif 5 <= 10 }}Bar {{ end }}Baz', 'Bar Baz'
39
+ assert_scribble_render '{{ if 5 != 3 }}Foo {{ elsif 1.zero }}Bar {{ end }}Baz', 'Foo Baz'
40
+ assert_scribble_render '{{ if (0.nonzero) }}Foo {{ elsif 5 < 0 }}Bar {{ end }}Baz', 'Baz'
41
+ end
42
+
43
+ it 'casts other expressions to booleans' do
44
+ assert_scribble_render "{{ if 1 + 1 }}Foo {{ elsif 'foo'.replace('foo', '') }}Bar {{ end }}Baz", 'Foo Baz'
45
+ assert_scribble_render "{{ if 1 - 1 }}Foo {{ elsif 3 * 'foo' }}Bar {{ end }}Baz", 'Bar Baz'
46
+ assert_scribble_render "{{ if ' ' }}Foo {{ elsif ' '.strip }}Bar {{ end }}Baz", 'Foo Baz'
47
+ assert_scribble_render "{{ if '' * 5 }}Foo {{ elsif 0.abs }}Bar {{ end }}Baz", 'Baz'
48
+ end
49
+ end
@@ -0,0 +1,71 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe Scribble::Methods::Layout do
4
+ it 'loads and renders a layout template' do
5
+ loader = MockLoader.new test: 'Foo {{ content }} Baz'
6
+ assert_scribble_render "{{ layout 'test' }}Bar{{end}}", 'Foo Bar Baz', template: {loader: loader}
7
+ end
8
+
9
+ it 'evaluates expressions in the template' do
10
+ loader = MockLoader.new test: "{{ 'Foo' * 2 }} {{ content.repeat(2) }} Baz"
11
+ assert_scribble_render "{{ layout 'test' }}Bar{{end}}", 'FooFoo BarBar Baz', template: {loader: loader}
12
+ end
13
+
14
+ # Access
15
+
16
+ it 'has access to template methods' do
17
+ loader = MockLoader.new test: 'Foo {{ if true }}{{ content }} {{ end }}Baz'
18
+ assert_scribble_render "{{ layout 'test' }}Bar{{end}}", 'Foo Bar Baz', template: {loader: loader}
19
+ end
20
+
21
+ it 'has access to template variables' do
22
+ loader = MockLoader.new test: 'Foo {{ content }} Baz {{ 12 }}'
23
+ assert_scribble_render "{{ layout 'test' }}Bar{{end}}", 'Foo Bar Baz 12', template: {loader: loader}, variables: {foo: 12}
24
+ end
25
+
26
+ it 'has access to layout variables' do
27
+ skip # Implement var first
28
+ end
29
+
30
+ # Passing object and nesting
31
+
32
+ it 'exposes a second argument as a variable' do
33
+ loader = MockLoader.new test: '{{ test }} {{ content }}'
34
+ assert_scribble_render "{{ layout 'test', 'Foo' }}Bar {{end}}Baz", 'Foo Bar Baz', template: {loader: loader}
35
+ end
36
+
37
+ it 'exposes a second argument as a variable when nested' do
38
+ loader = MockLoader.new foo: "{{ foo }}{{ layout 'bar', content }}{{ foo }}{{ end }}{{ foo }}", bar: '{{ bar }}{{ content }}{{ bar }}'
39
+ assert_scribble_render "0{{ layout 'foo', 1 }}2{{end}}0", '0121210', template: {loader: loader}
40
+ end
41
+
42
+ # Formats
43
+
44
+ it 'adopts context format when no layout format is specified' do
45
+ loader = MockLoader.new foo: '{{ content }}'
46
+ assert_scribble_render "{{ layout 'foo' }}FOO{{ end }}", 'FOO', template: {loader: loader, format: :template_format}
47
+ end
48
+
49
+ it "won't need converter to render a layout in template format" do
50
+ loader = MockLoader.new foo: ['{{ content }}', :template_format]
51
+ assert_scribble_render "{{ layout 'foo' }}FOO{{ end }}", 'FOO', template: {loader: loader, format: :template_format}
52
+ end
53
+
54
+ it "can't render a layout with a format without suitable converters back and forth" do
55
+ loader = MockLoader.new foo: ['{{ content }}BAR', :layout_format]
56
+ c1 = MockConverter.new :layout_format, :template_format
57
+ c2 = MockConverter.new :template_format, :layout_format
58
+
59
+ assert_raises_message 'No suitable converter' do
60
+ Scribble::Template.new("{{ layout 'foo' }}FOO{{ end }}", loader: loader, format: :template_format, converters: [c1]).render
61
+ end
62
+
63
+ assert_raises_message 'No suitable converter' do
64
+ Scribble::Template.new("{{ layout 'foo' }}FOO{{ end }}", loader: loader, format: :template_format, converters: [c2]).render
65
+ end
66
+
67
+ assert_scribble_render "{{ layout 'foo' }}FOO{{ end }}", 'layout_format > template_format(template_format > layout_format(FOO)BAR)',
68
+ template: {loader: loader, format: :template_format, converters: [c1, c2]}
69
+ end
70
+
71
+ end
@@ -0,0 +1,85 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe Scribble::Methods::Partial do
4
+ it 'loads and renders a partial template' do
5
+ loader = MockLoader.new test: 'Foo Bar Baz'
6
+ assert_scribble_render "{{ partial 'test' }}", 'Foo Bar Baz', template: {loader: loader}
7
+ end
8
+
9
+ it 'evaluates expressions in the template' do
10
+ loader = MockLoader.new test: '{{ 1 + 2 }}'
11
+ assert_scribble_render "{{ partial 'test' }}", '3', template: {loader: loader}
12
+ end
13
+
14
+ # Access
15
+
16
+ it 'has access to template methods' do
17
+ loader = MockLoader.new test: '{{ if true }}foo{{ else }}bar{{ end }}'
18
+ assert_scribble_render "{{ partial 'test' }}", 'foo', template: {loader: loader}
19
+ end
20
+
21
+ it 'has access to template variables' do
22
+ loader = MockLoader.new test: 'foo={{ foo }}, bar={{ bar }}, foo * bar={{ foo * bar }}'
23
+ assert_scribble_render "{{ partial 'test' }}", 'foo=3, bar=Foo, foo * bar=FooFooFoo', template: {loader: loader}, variables: {foo: 3, bar: 'Foo'}
24
+ end
25
+
26
+ it 'has access to template variables when nested' do
27
+ loader = MockLoader.new test: "{{ partial 'nested' }}", nested: '{{ foo }}'
28
+ assert_scribble_render "foo={{ partial 'test' }}", 'foo=3', template: {loader: loader}, variables: {foo: 3}
29
+ end
30
+
31
+ # Passing object
32
+
33
+ it 'exposes a second argument as a variable' do
34
+ loader = MockLoader.new test: '{{ test }}'
35
+ assert_scribble_render "{{ partial 'test', 'foo' }}", 'foo', template: {loader: loader}, variables: {foo: 3}
36
+ end
37
+
38
+ # Formats
39
+
40
+ it 'ignores partial format if no render format is specified' do
41
+ loader = MockLoader.new foo: ['FOO', :partial_format]
42
+ assert_scribble_render "{{ partial 'foo' }}", 'FOO', template: {loader: loader}
43
+ end
44
+
45
+ it 'adopts context format when no partial format is specified' do
46
+ loader = MockLoader.new foo: 'FOO'
47
+ assert_scribble_render "{{ partial 'foo' }}", 'FOO', template: {loader: loader, format: :template_format}
48
+ end
49
+
50
+ it "can't render a partial with format without a suitable converter" do
51
+ loader = MockLoader.new foo: ['FOO', :partial_format]
52
+ assert_raises_message 'No suitable converter' do
53
+ Scribble::Template.new("{{ partial 'foo' }}", loader: loader, format: :template_format).render
54
+ end
55
+ end
56
+
57
+ it "won't need converter to render a partial in template format" do
58
+ loader = MockLoader.new foo: ['FOO', :template_format]
59
+ assert_scribble_render "{{ partial 'foo' }}", 'FOO', template: {loader: loader, format: :template_format}
60
+ end
61
+
62
+ it "converts a partial with format to the template format using a suitable converter" do
63
+ loader = MockLoader.new foo: ['FOO', :partial_format]
64
+ converter = MockConverter.new :partial_format, :template_format
65
+ assert_scribble_render "{{ partial 'foo' }}", 'partial_format > template_format(FOO)',
66
+ template: {loader: loader, format: :template_format, converters: [converter]}
67
+ end
68
+
69
+ # Formats and nested partials
70
+
71
+ it "won't converted nested partials with the same format" do
72
+ loader = MockLoader.new test: ["{{ partial 'nested' }}", :partial_format], nested: ['NESTED', :partial_format]
73
+ converter = MockConverter.new :partial_format, :template_format
74
+ assert_scribble_render "{{ partial 'test' }}", 'partial_format > template_format(NESTED)',
75
+ template: {loader: loader, format: :template_format, converters: [converter]}
76
+ end
77
+
78
+ it "converts nested partials" do
79
+ loader = MockLoader.new test: ["{{ partial 'nested' }}", :partial_format], nested: ['NESTED', :nested_partial_format]
80
+ c1 = MockConverter.new :partial_format, :template_format
81
+ c2 = MockConverter.new :nested_partial_format, :partial_format
82
+ assert_scribble_render "{{ partial 'test' }}", 'partial_format > template_format(nested_partial_format > partial_format(NESTED))',
83
+ template: {loader: loader, format: :template_format, converters: [c1, c2]}
84
+ end
85
+ end
@@ -0,0 +1,10 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe Scribble::Methods::Times do
4
+ it 'repeats a block of content x times' do
5
+ assert_scribble_render "{{ 0.times }}Foo Bar {{ end }}", ''
6
+ assert_scribble_render "{{ 1.times }}Foo Bar {{ end }}", 'Foo Bar '
7
+ assert_scribble_render "{{ 3.times }}Foo Bar {{ end }}", 'Foo Bar Foo Bar Foo Bar '
8
+ assert_scribble_render "{{ 5.times }}Foo Bar {{ end }}", 'Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar '
9
+ end
10
+ end
@@ -0,0 +1,162 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe 'scribble boolean' do
4
+ it 'can be used as a literal' do
5
+ assert_scribble_render '{{ true }}', 'true'
6
+ assert_scribble_render '{{ false }}', 'false'
7
+ end
8
+
9
+ it 'supports method and operator for logical or' do
10
+ assert_scribble_render '{{ false.or true }}', 'true'
11
+ assert_scribble_render '{{ true.or true }}', 'true'
12
+ assert_scribble_render '{{ false.or false }}', 'false'
13
+ assert_scribble_render '{{ true.or false }}', 'true'
14
+ assert_scribble_render '{{ false.or 2 }}', 'true'
15
+ assert_scribble_render '{{ true.or 2 }}', 'true'
16
+ assert_scribble_render '{{ false.or 0 }}', 'false'
17
+ assert_scribble_render '{{ true.or 0 }}', 'true'
18
+ assert_scribble_render "{{ false.or 'foo' }}", 'true'
19
+ assert_scribble_render "{{ true.or 'foo' }}", 'true'
20
+ assert_scribble_render "{{ false.or '' }}", 'false'
21
+ assert_scribble_render "{{ true.or '' }}", 'true'
22
+ assert_scribble_render '{{ false | true }}', 'true'
23
+ assert_scribble_render '{{ true | true }}', 'true'
24
+ assert_scribble_render '{{ false | false }}', 'false'
25
+ assert_scribble_render '{{ true | false }}', 'true'
26
+ assert_scribble_render '{{ false | 2 }}', 'true'
27
+ assert_scribble_render '{{ true | 2 }}', 'true'
28
+ assert_scribble_render '{{ false | 0 }}', 'false'
29
+ assert_scribble_render '{{ true | 0 }}', 'true'
30
+ assert_scribble_render "{{ false | 'foo' }}", 'true'
31
+ assert_scribble_render "{{ true | 'foo' }}", 'true'
32
+ assert_scribble_render "{{ false | '' }}", 'false'
33
+ assert_scribble_render "{{ true | '' }}", 'true'
34
+ end
35
+
36
+ it 'supports method and operator for logical and' do
37
+ assert_scribble_render '{{ false.and true }}', 'false'
38
+ assert_scribble_render '{{ true.and true }}', 'true'
39
+ assert_scribble_render '{{ false.and false }}', 'false'
40
+ assert_scribble_render '{{ true.and false }}', 'false'
41
+ assert_scribble_render '{{ false.and 2 }}', 'false'
42
+ assert_scribble_render '{{ true.and 2 }}', 'true'
43
+ assert_scribble_render '{{ false.and 0 }}', 'false'
44
+ assert_scribble_render '{{ true.and 0 }}', 'false'
45
+ assert_scribble_render "{{ false.and 'foo' }}", 'false'
46
+ assert_scribble_render "{{ true.and 'foo' }}", 'true'
47
+ assert_scribble_render "{{ false.and '' }}", 'false'
48
+ assert_scribble_render "{{ true.and '' }}", 'false'
49
+ assert_scribble_render '{{ false & true }}', 'false'
50
+ assert_scribble_render '{{ true & true }}', 'true'
51
+ assert_scribble_render '{{ false & false }}', 'false'
52
+ assert_scribble_render '{{ true & false }}', 'false'
53
+ assert_scribble_render '{{ false & 2 }}', 'false'
54
+ assert_scribble_render '{{ true & 2 }}', 'true'
55
+ assert_scribble_render '{{ false & 0 }}', 'false'
56
+ assert_scribble_render '{{ true & 0 }}', 'false'
57
+ assert_scribble_render "{{ false & 'foo' }}", 'false'
58
+ assert_scribble_render "{{ true & 'foo' }}", 'true'
59
+ assert_scribble_render "{{ false & '' }}", 'false'
60
+ assert_scribble_render "{{ true & '' }}", 'false'
61
+ end
62
+
63
+ it 'can equal another boolean' do
64
+ assert_scribble_render '{{ true.equals true }}', 'true'
65
+ assert_scribble_render '{{ true.equals false }}', 'false'
66
+ assert_scribble_render '{{ true = true }}', 'true'
67
+ assert_scribble_render '{{ true = false }}', 'false'
68
+ end
69
+
70
+ it 'does not equal another type' do
71
+ assert_scribble_render '{{ true.equals 3 }}', 'false'
72
+ assert_scribble_render "{{ true.equals 'foo' }}", 'false'
73
+ assert_scribble_render '{{ true = 3 }}', 'false'
74
+ assert_scribble_render "{{ true = 'foo' }}", 'false'
75
+ end
76
+
77
+ it 'can differ from another boolean' do
78
+ assert_scribble_render '{{ true.differs true }}', 'false'
79
+ assert_scribble_render '{{ true.differs false }}', 'true'
80
+ assert_scribble_render '{{ true != true }}', 'false'
81
+ assert_scribble_render '{{ true != false }}', 'true'
82
+ end
83
+
84
+ it 'differs from another type' do
85
+ assert_scribble_render '{{ true.differs 3 }}', 'true'
86
+ assert_scribble_render "{{ true.differs 'foo' }}", 'true'
87
+ assert_scribble_render '{{ true != 3 }}', 'true'
88
+ assert_scribble_render "{{ true != 'foo' }}", 'true'
89
+ end
90
+
91
+ it 'can not be compared' do
92
+ assert_scribble_raises "{{ true.greater 'foo' }}"
93
+ assert_scribble_raises '{{ true.greater 3 }}'
94
+ assert_scribble_raises '{{ true.greater true }}'
95
+ assert_scribble_raises "{{ true > 'foo' }}"
96
+ assert_scribble_raises '{{ true > 3 }}'
97
+ assert_scribble_raises '{{ true > true }}'
98
+ assert_scribble_raises "{{ true.less 'foo' }}"
99
+ assert_scribble_raises '{{ true.less 3 }}'
100
+ assert_scribble_raises '{{ true.less true }}'
101
+ assert_scribble_raises "{{ true < 'foo' }}"
102
+ assert_scribble_raises '{{ true < 3 }}'
103
+ assert_scribble_raises '{{ true < true }}'
104
+ assert_scribble_raises "{{ true.greater_or_equal 'foo' }}"
105
+ assert_scribble_raises '{{ true.greater_or_equal 3 }}'
106
+ assert_scribble_raises '{{ true.greater_or_equal true }}'
107
+ assert_scribble_raises "{{ true >= 'foo' }}"
108
+ assert_scribble_raises '{{ true >= 3 }}'
109
+ assert_scribble_raises '{{ true >= true }}'
110
+ assert_scribble_raises "{{ true.less_or_equal 'foo' }}"
111
+ assert_scribble_raises '{{ true.less_or_equal 3 }}'
112
+ assert_scribble_raises '{{ true.less_or_equal true }}'
113
+ assert_scribble_raises "{{ true <= 'foo' }}"
114
+ assert_scribble_raises '{{ true <= 3 }}'
115
+ assert_scribble_raises '{{ true <= true }}'
116
+ end
117
+
118
+ it 'does not support calculations' do
119
+ assert_scribble_raises '{{ true.add 3 }}'
120
+ assert_scribble_raises "{{ true.add 'foo' }}"
121
+ assert_scribble_raises '{{ true.add true }}'
122
+ assert_scribble_raises '{{ true + 3 }}'
123
+ assert_scribble_raises "{{ true + 'foo' }}"
124
+ assert_scribble_raises '{{ true + true }}'
125
+ assert_scribble_raises '{{ true.subtract 3 }}'
126
+ assert_scribble_raises "{{ true.subtract 'foo' }}"
127
+ assert_scribble_raises '{{ true.subtract true }}'
128
+ assert_scribble_raises '{{ true - 3 }}'
129
+ assert_scribble_raises "{{ true - 'foo' }}"
130
+ assert_scribble_raises '{{ true - true }}'
131
+ assert_scribble_raises '{{ true.multiply 3 }}'
132
+ assert_scribble_raises "{{ true.multiply 'foo' }}"
133
+ assert_scribble_raises '{{ true.multiply true }}'
134
+ assert_scribble_raises '{{ true * 3 }}'
135
+ assert_scribble_raises "{{ true * 'foo' }}"
136
+ assert_scribble_raises '{{ true * true }}'
137
+ assert_scribble_raises '{{ true.divide 3 }}'
138
+ assert_scribble_raises "{{ true.divide 'foo' }}"
139
+ assert_scribble_raises '{{ true.divide true }}'
140
+ assert_scribble_raises '{{ true / 3 }}'
141
+ assert_scribble_raises "{{ true / 'foo' }}"
142
+ assert_scribble_raises '{{ true / true }}'
143
+ assert_scribble_raises '{{ true.remainder 3 }}'
144
+ assert_scribble_raises "{{ true.remainder 'foo' }}"
145
+ assert_scribble_raises '{{ true.remainder true }}'
146
+ assert_scribble_raises '{{ true % 3 }}'
147
+ assert_scribble_raises "{{ true % 'foo' }}"
148
+ assert_scribble_raises '{{ true % true }}'
149
+ end
150
+
151
+ it 'can not be negated' do
152
+ assert_scribble_raises '{{ true.negative }}'
153
+ assert_scribble_raises '{{ -true }}'
154
+ end
155
+
156
+ it 'can be logically negated' do
157
+ assert_scribble_render '{{ true.not }}', 'false'
158
+ assert_scribble_render '{{ false.not }}', 'true'
159
+ assert_scribble_render '{{ !!true }}', 'true'
160
+ assert_scribble_render '{{ !!!true }}', 'false'
161
+ end
162
+ end