liquor 0.1.1 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -9
- data/Gemfile +7 -0
- data/Guardfile +11 -0
- data/MIT-LICENSE +6 -2
- data/README.md +4 -122
- data/Rakefile +20 -23
- data/doc/language-spec.html +768 -0
- data/doc/language-spec.md +698 -0
- data/lib/liquor.rb +39 -68
- data/lib/liquor/ast_tools.rb +28 -0
- data/lib/liquor/compiler.rb +110 -0
- data/lib/liquor/context.rb +76 -254
- data/lib/liquor/diagnostics.rb +151 -0
- data/lib/liquor/drop/drop.rb +168 -0
- data/lib/liquor/drop/drop_delegation.rb +24 -0
- data/lib/liquor/drop/drop_scope.rb +118 -0
- data/lib/liquor/drop/dropable.rb +17 -0
- data/lib/liquor/emitter.rb +313 -0
- data/lib/liquor/extensions/kaminari.rb +14 -0
- data/lib/liquor/extensions/pagination.rb +235 -0
- data/lib/liquor/extensions/rails.rb +97 -0
- data/lib/liquor/extensions/thinking_sphinx.rb +14 -0
- data/lib/liquor/extensions/tire.rb +30 -0
- data/lib/liquor/external.rb +79 -0
- data/lib/liquor/function.rb +94 -0
- data/lib/liquor/grammar/lexer.rb +1223 -0
- data/lib/liquor/grammar/lexer.rl +297 -0
- data/lib/liquor/grammar/parser.racc +288 -0
- data/lib/liquor/grammar/parser.rb +885 -0
- data/lib/liquor/library.rb +41 -0
- data/lib/liquor/manager.rb +146 -0
- data/lib/liquor/runtime.rb +167 -0
- data/lib/liquor/stdlib/builtin_functions.rb +315 -0
- data/lib/liquor/stdlib/builtin_tags.rb +228 -0
- data/lib/liquor/stdlib/html_truncater.rb +162 -0
- data/lib/liquor/stdlib/partial_tags.rb +76 -0
- data/lib/liquor/tag.rb +83 -14
- data/lib/liquor/version.rb +1 -1
- data/liquor.gemspec +29 -6
- data/spec/builtins_spec.rb +264 -0
- data/spec/compiler_spec.rb +136 -0
- data/spec/context_spec.rb +49 -0
- data/spec/drop_delegation_spec.rb +21 -0
- data/spec/drop_spec.rb +222 -0
- data/spec/errors_spec.rb +40 -0
- data/spec/external_spec.rb +207 -0
- data/spec/function_spec.rb +80 -0
- data/spec/lexer_spec.rb +173 -0
- data/spec/library_spec.rb +18 -0
- data/spec/manager_spec.rb +84 -0
- data/spec/parser_spec.rb +381 -0
- data/spec/partials_spec.rb +74 -0
- data/spec/runtime_spec.rb +97 -0
- data/spec/spec_helper.rb +94 -0
- data/spec/tag_spec.rb +7 -0
- metadata +216 -173
- data/AUTHORS +0 -2
- data/CHANGELOG +0 -48
- data/Gemfile.lock +0 -91
- data/History.txt +0 -44
- data/LICENSE +0 -23
- data/example/server/example_servlet.rb +0 -37
- data/example/server/liquid_servlet.rb +0 -28
- data/example/server/liquor_servlet.rb +0 -28
- data/example/server/server.rb +0 -12
- data/example/server/templates/index.liquid +0 -6
- data/example/server/templates/index.liquor +0 -6
- data/example/server/templates/products.liquid +0 -45
- data/example/server/templates/products.liquor +0 -45
- data/init.rb +0 -8
- data/lib/extras/liquid_view.rb +0 -51
- data/lib/extras/liquor_view.rb +0 -51
- data/lib/liquor/block.rb +0 -101
- data/lib/liquor/condition.rb +0 -120
- data/lib/liquor/document.rb +0 -17
- data/lib/liquor/drop.rb +0 -256
- data/lib/liquor/errors.rb +0 -11
- data/lib/liquor/extensions.rb +0 -72
- data/lib/liquor/file_system.rb +0 -62
- data/lib/liquor/htmltags.rb +0 -74
- data/lib/liquor/module_ex.rb +0 -60
- data/lib/liquor/standardfilters.rb +0 -315
- data/lib/liquor/strainer.rb +0 -58
- data/lib/liquor/tags/assign.rb +0 -33
- data/lib/liquor/tags/capture.rb +0 -35
- data/lib/liquor/tags/case.rb +0 -83
- data/lib/liquor/tags/comment.rb +0 -9
- data/lib/liquor/tags/content_for.rb +0 -54
- data/lib/liquor/tags/cycle.rb +0 -59
- data/lib/liquor/tags/for.rb +0 -136
- data/lib/liquor/tags/if.rb +0 -80
- data/lib/liquor/tags/ifchanged.rb +0 -20
- data/lib/liquor/tags/include.rb +0 -56
- data/lib/liquor/tags/unless.rb +0 -33
- data/lib/liquor/tags/yield.rb +0 -49
- data/lib/liquor/template.rb +0 -181
- data/lib/liquor/variable.rb +0 -52
- data/performance/shopify.rb +0 -92
- data/performance/shopify/comment_form.rb +0 -33
- data/performance/shopify/database.rb +0 -45
- data/performance/shopify/json_filter.rb +0 -7
- data/performance/shopify/liquid.rb +0 -18
- data/performance/shopify/liquor.rb +0 -18
- data/performance/shopify/money_filter.rb +0 -18
- data/performance/shopify/paginate.rb +0 -93
- data/performance/shopify/shop_filter.rb +0 -98
- data/performance/shopify/tag_filter.rb +0 -25
- data/performance/shopify/vision.database.yml +0 -945
- data/performance/shopify/weight_filter.rb +0 -11
- data/performance/tests/dropify/article.liquid +0 -74
- data/performance/tests/dropify/blog.liquid +0 -33
- data/performance/tests/dropify/cart.liquid +0 -66
- data/performance/tests/dropify/collection.liquid +0 -22
- data/performance/tests/dropify/index.liquid +0 -47
- data/performance/tests/dropify/page.liquid +0 -8
- data/performance/tests/dropify/product.liquid +0 -68
- data/performance/tests/dropify/theme.liquid +0 -105
- data/performance/tests/ripen/article.liquid +0 -74
- data/performance/tests/ripen/blog.liquid +0 -13
- data/performance/tests/ripen/cart.liquid +0 -54
- data/performance/tests/ripen/collection.liquid +0 -29
- data/performance/tests/ripen/index.liquid +0 -32
- data/performance/tests/ripen/page.liquid +0 -4
- data/performance/tests/ripen/product.liquid +0 -75
- data/performance/tests/ripen/theme.liquid +0 -85
- data/performance/tests/tribble/404.liquid +0 -56
- data/performance/tests/tribble/article.liquid +0 -98
- data/performance/tests/tribble/blog.liquid +0 -41
- data/performance/tests/tribble/cart.liquid +0 -134
- data/performance/tests/tribble/collection.liquid +0 -70
- data/performance/tests/tribble/index.liquid +0 -94
- data/performance/tests/tribble/page.liquid +0 -56
- data/performance/tests/tribble/product.liquid +0 -116
- data/performance/tests/tribble/search.liquid +0 -51
- data/performance/tests/tribble/theme.liquid +0 -90
- data/performance/tests/vogue/article.liquid +0 -66
- data/performance/tests/vogue/blog.liquid +0 -32
- data/performance/tests/vogue/cart.liquid +0 -58
- data/performance/tests/vogue/collection.liquid +0 -19
- data/performance/tests/vogue/index.liquid +0 -22
- data/performance/tests/vogue/page.liquid +0 -3
- data/performance/tests/vogue/product.liquid +0 -62
- data/performance/tests/vogue/theme.liquid +0 -122
- data/test/assign_test.rb +0 -11
- data/test/block_test.rb +0 -58
- data/test/capture_test.rb +0 -41
- data/test/condition_test.rb +0 -115
- data/test/content_for_test.rb +0 -15
- data/test/context_test.rb +0 -479
- data/test/drop_test.rb +0 -162
- data/test/error_handling_test.rb +0 -89
- data/test/extra/breakpoint.rb +0 -547
- data/test/extra/caller.rb +0 -80
- data/test/file_system_test.rb +0 -30
- data/test/filter_test.rb +0 -147
- data/test/helper.rb +0 -24
- data/test/html_tag_test.rb +0 -31
- data/test/if_else_test.rb +0 -139
- data/test/include_tag_test.rb +0 -129
- data/test/module_ex_test.rb +0 -89
- data/test/output_test.rb +0 -121
- data/test/parsing_quirks_test.rb +0 -54
- data/test/regexp_test.rb +0 -45
- data/test/security_test.rb +0 -41
- data/test/standard_filter_test.rb +0 -170
- data/test/standard_tag_test.rb +0 -405
- data/test/statements_test.rb +0 -137
- data/test/strainer_test.rb +0 -27
- data/test/template_test.rb +0 -82
- data/test/test_helper.rb +0 -28
- data/test/unless_else_test.rb +0 -27
- data/test/variable_test.rb +0 -173
- data/test/yield_test.rb +0 -24
@@ -0,0 +1,49 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Liquor::Context do
|
4
|
+
before do
|
5
|
+
@compiler = Liquor::Compiler.new
|
6
|
+
@context = Liquor::Context.new(@compiler, ['ext', 'ext2'])
|
7
|
+
end
|
8
|
+
|
9
|
+
it "declares variables" do
|
10
|
+
@context.type('a').should == :free
|
11
|
+
@context.declare 'a'
|
12
|
+
@context.type('a').should == :variable
|
13
|
+
end
|
14
|
+
|
15
|
+
it "verifies variable names" do
|
16
|
+
expect { @context.declare 'null' }.to raise_error(Liquor::NameError)
|
17
|
+
expect { @context.declare 'a' }.not_to raise_error
|
18
|
+
expect { @context.declare 'a' }.not_to raise_error
|
19
|
+
expect { @context.declare 'ext' }.not_to raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it "mangles names" do
|
23
|
+
@context.declare '_env'
|
24
|
+
@context.access('_env').should_not be_nil
|
25
|
+
@context.access('_env').should_not == '_env'
|
26
|
+
end
|
27
|
+
|
28
|
+
it "supports nesting" do
|
29
|
+
@context.nest do
|
30
|
+
@context.declare 'test'
|
31
|
+
end
|
32
|
+
expect { @context.access 'test' }.to raise_error(Liquor::NameError)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "shadows variables" do
|
36
|
+
@context.declare 'test'
|
37
|
+
var_a = @context.access 'test'
|
38
|
+
|
39
|
+
var_b = @context.nest do
|
40
|
+
@context.declare 'test'
|
41
|
+
@context.access 'test'
|
42
|
+
end
|
43
|
+
|
44
|
+
var_c = @context.access 'test'
|
45
|
+
|
46
|
+
var_a.should_not == var_b
|
47
|
+
var_a.should == var_c
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'liquor/drop/drop'
|
2
|
+
|
3
|
+
describe Liquor::DropDelegation do
|
4
|
+
before :all do
|
5
|
+
class TestModel
|
6
|
+
include Liquor::Dropable
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestModelDrop < Liquor::Drop
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
after :all do
|
14
|
+
Object.send :remove_const, :TestModel
|
15
|
+
Object.send :remove_const, :TestModelDrop
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should correctly unwrap drop classes" do
|
19
|
+
Liquor::DropDelegation.unwrap_drop_class(TestModelDrop).should == TestModel
|
20
|
+
end
|
21
|
+
end
|
data/spec/drop_spec.rb
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "sqlite3"
|
4
|
+
require "liquor/drop/drop"
|
5
|
+
|
6
|
+
ActiveRecord::Base.establish_connection(
|
7
|
+
adapter: 'sqlite3',
|
8
|
+
database: ':memory:',
|
9
|
+
)
|
10
|
+
|
11
|
+
ActiveRecord::Schema.define force: true do
|
12
|
+
create_table "users", force: true do |t|
|
13
|
+
t.string "login"
|
14
|
+
t.string "email"
|
15
|
+
t.string "occupation"
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table "articles", force: true do |t|
|
19
|
+
t.integer "user_id"
|
20
|
+
t.string "name"
|
21
|
+
t.boolean "published"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Models
|
26
|
+
|
27
|
+
class User < ActiveRecord::Base
|
28
|
+
include Liquor::Dropable
|
29
|
+
|
30
|
+
has_many :articles
|
31
|
+
|
32
|
+
scope :with_login, ->(login) { where('login = ?', login) }
|
33
|
+
scope :with_id, ->(id) { where('id = ?', id) }
|
34
|
+
end
|
35
|
+
|
36
|
+
class Article < ActiveRecord::Base
|
37
|
+
include Liquor::Dropable
|
38
|
+
|
39
|
+
belongs_to :user
|
40
|
+
|
41
|
+
scope :published, -> { where('published = ?', true) }
|
42
|
+
end
|
43
|
+
|
44
|
+
dhh = User.create login: 'dhh', email: 'dhh@loudthinking.org', occupation: 'developer'
|
45
|
+
dhh.articles.create name: 'java sucks', published: false
|
46
|
+
dhh.articles.create name: 'rails rules', published: true
|
47
|
+
|
48
|
+
me = User.create login: 'me', email: 'vassily@poupkin.org', occupation: 'developer'
|
49
|
+
me.articles.create name: 'hello world', published: true
|
50
|
+
|
51
|
+
nate = User.create login: 'xnutsive', email: 'nat@evl.ms', occupation: 'manager'
|
52
|
+
|
53
|
+
# Drops
|
54
|
+
|
55
|
+
class UserDrop < Liquor::Drop
|
56
|
+
attributes :id, :login, :email
|
57
|
+
scopes :with_login, :with_id
|
58
|
+
|
59
|
+
has_many :articles, scope: [ :published ]
|
60
|
+
end
|
61
|
+
|
62
|
+
class ArticleDrop < Liquor::Drop
|
63
|
+
attributes :name, :published
|
64
|
+
scopes :published
|
65
|
+
|
66
|
+
belongs_to :user
|
67
|
+
end
|
68
|
+
|
69
|
+
describe Liquor::Drop do
|
70
|
+
before do
|
71
|
+
@me = User.find_by_login 'me'
|
72
|
+
@dhh = User.find_by_login 'dhh'
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should export attributes" do
|
76
|
+
strukt = Struct.new(:a, :b)
|
77
|
+
klass = Class.new(Liquor::Drop) do
|
78
|
+
attributes :a, :b
|
79
|
+
end
|
80
|
+
|
81
|
+
datum = strukt.new(1, "hello")
|
82
|
+
drop = klass.new(datum)
|
83
|
+
|
84
|
+
exec('{{ drop.a }} {{ drop.b }}', drop: drop).should == '1 hello'
|
85
|
+
expect { exec('{{ drop.c }}') }.to raise_error
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should allow iterating" do
|
89
|
+
expect {
|
90
|
+
exec(%|{% for user in: users do: %}{{ user.id }}{% end for %}|, users: User.to_drop)
|
91
|
+
}.not_to raise_error
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should walk relations and stuff" do
|
95
|
+
exec('{{ user.login }}', user: @dhh.to_drop).should == 'dhh'
|
96
|
+
exec(%|{% for article in: user.articles do: %}{{ article.name }}, {% end for %}|,
|
97
|
+
user: @dhh.to_drop).strip.should == 'rails rules,'
|
98
|
+
exec(%|{{ size(articles) }}|, articles: Article.to_drop).should == '3'
|
99
|
+
exec(%|{{ size(articles.published) }}|, articles: Article.to_drop).should == '2'
|
100
|
+
exec(%|{{ size(users.with_login('dhh')) }}|, users: User.to_drop).should == '1'
|
101
|
+
exec(%|{% if article.user == null then: %}ok{% end if %}|, article: Article.new.to_drop).should == 'ok'
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should support generic find_by" do
|
105
|
+
exec(%|{{ users.find_by(login: "dhh").email }}|, users: User.to_drop).should == 'dhh@loudthinking.org'
|
106
|
+
exec(%|{{ users.find_by(email: "vassily@poupkin.org").login }}|, users: User.to_drop).should == 'me'
|
107
|
+
exec(%|{{ users.find_by(id: user).email }}|, users: User.to_drop, user: @dhh.to_drop).should == 'dhh@loudthinking.org'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return null from find_by" do
|
111
|
+
exec(%|{% if users.find_by(login: "123") == null then: %}ok{% end if %}|, users: User.to_drop).should == 'ok'
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should support generic find_all_by and return a tuple" do
|
115
|
+
exec(%|{{ size(users.find_all_by(occupation: "developer")) }}|, users: User.to_drop).should == '2'
|
116
|
+
exec(%|{{ size(users.find_all_by(occupation: "manager")) }}|, users: User.to_drop).should == '1'
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should support reversing" do
|
120
|
+
ltr = exec(%|{% for user in: users do: %}{{ user.id }}{% end for %}|, users: User.to_drop)
|
121
|
+
rtl = exec(%|{% for user in: users.reverse do: %}{{ user.id }}{% end for %}|, users: User.to_drop)
|
122
|
+
ltr.should == rtl.reverse
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should support except" do
|
126
|
+
res = exec(%|{% for user in: users.except(users.find_by(login: 'xnutsive')) do: %}{{ user.login }},{% end for %}|, users: User.to_drop)
|
127
|
+
res.split(',').sort.should == %w(me dhh).sort
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should support find_except_by" do
|
131
|
+
res = exec(%|{% for user in: users.find_except_by(login: 'xnutsive') do: %}{{ user.login }},{% end for %}|, users: User.to_drop)
|
132
|
+
res.split(',').sort.should == %w(me dhh).sort
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should not fail if the [] argument is out of range" do
|
136
|
+
exec(%|{% if users[5] == null then: %}ok{% end if %}|, users: User.to_drop).should == 'ok'
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should provide [] access to the elements, returned by find_all_by function" do
|
140
|
+
exec(%|
|
141
|
+
{% assign found_users = users.find_all_by(occupation: "developer") %}
|
142
|
+
{{ found_users[0].login }}
|
143
|
+
|, users: User.to_drop).strip.should == 'dhh'
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should accept scope returned by find_all_by in for statements" do
|
147
|
+
exec(%|
|
148
|
+
{% for user in: users.find_all_by(occupation: "developer") do: %}
|
149
|
+
{{ user.login }}
|
150
|
+
{% end for %}
|
151
|
+
|, users: User.to_drop).split.should == %w[dhh me]
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should accept scope returned by find_all into empty() function" do
|
155
|
+
exec(%|{% if !is_empty(users.find_all_by(occupation: "developer")) then: %}it works{%end if%}|, users: User.to_drop).should == "it works"
|
156
|
+
exec(%|{% if is_empty(users.find_all_by(occupation: "idiot")) then: %}it works{% end if%}|, users: User.to_drop).should == "it works"
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should support #pluck" do
|
160
|
+
exec(%!{{ users.pluck('login') | join with: ', ' }}!, users: User.to_drop).should == 'dhh, me, xnutsive'
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should export model name from Drop and Drop::Scope" do
|
164
|
+
exec(%!{{ users.entity }}!, users: User.to_drop).should == 'User'
|
165
|
+
exec(%!{{ users.first.entity }}!, users: User.to_drop).should == 'User'
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should return intact source" do
|
169
|
+
@dhh.to_drop.source.should == @dhh
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should support equality" do
|
173
|
+
(@dhh.to_drop == @dhh.to_drop).should == true
|
174
|
+
(@dhh.to_drop.eql? @dhh.to_drop).should == true
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should support include?" do
|
178
|
+
lib = Module.new do
|
179
|
+
include Liquor::Library
|
180
|
+
|
181
|
+
function "check", {
|
182
|
+
mandatory_named_args: {
|
183
|
+
collection: :any,
|
184
|
+
element: :any,
|
185
|
+
}
|
186
|
+
} do |arg, kw|
|
187
|
+
kw[:collection].include? kw[:element]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
compiler = Liquor::Compiler.new
|
192
|
+
lib.export compiler
|
193
|
+
code = compiler.compile!(parse(%|
|
194
|
+
{% if check(collection: collection element: element) then: %}
|
195
|
+
yes
|
196
|
+
{% end if %}
|
197
|
+
|, compiler), [:collection, :element])
|
198
|
+
|
199
|
+
code.call(collection: User.to_drop, element: @dhh.to_drop).
|
200
|
+
strip.should == 'yes'
|
201
|
+
code.call(collection: User.to_drop, element: User.new.to_drop).
|
202
|
+
strip.should == ''
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should support uniq'ing" do
|
206
|
+
@dhh.to_drop.hash.should == @dhh.to_drop.hash
|
207
|
+
[@me, @dhh, @dhh].map(&:to_drop).uniq.size.should == 2
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should unwrap arguments to derivative scopes" do
|
211
|
+
Liquor::Drop.unwrap_scope_arguments([ @me.to_drop ]).
|
212
|
+
should == [@me.id]
|
213
|
+
Liquor::Drop.unwrap_scope_arguments([ [@me.to_drop, @dhh.to_drop] ]).
|
214
|
+
should == [ [@me.id, @dhh.id] ]
|
215
|
+
Liquor::Drop.unwrap_scope_arguments([ 1, { a: @me.to_drop, b: @dhh.to_drop } ]).
|
216
|
+
should == [ 1, { a: @me.id, b: @dhh.id } ]
|
217
|
+
exec('{{ scope.with_id(obj).first.login }}', scope: User.to_drop, obj: @me.to_drop).
|
218
|
+
should == @me.login
|
219
|
+
Liquor::Drop.unwrap_scope_arguments([ User.order(:id).to_drop ]).
|
220
|
+
should == [ User.pluck(:id).sort ]
|
221
|
+
end
|
222
|
+
end
|
data/spec/errors_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Liquor::Diagnostic do
|
4
|
+
it "is not an error" do
|
5
|
+
diag = Liquor::Diagnostic.new("foobar")
|
6
|
+
diag.error?.should be_false
|
7
|
+
end
|
8
|
+
|
9
|
+
it "decorates source" do
|
10
|
+
source = "line 1\nthis is a diagnostic"
|
11
|
+
diag = Liquor::Diagnostic.new("foobar", line: 1, start: 10, end: 19)
|
12
|
+
diag.decorate(source).should == [
|
13
|
+
"this is a diagnostic",
|
14
|
+
" ^^^^^^^^^^"
|
15
|
+
]
|
16
|
+
diag.as_json.should == {
|
17
|
+
message: 'foobar',
|
18
|
+
is_error: false,
|
19
|
+
location: {
|
20
|
+
line: 1,
|
21
|
+
start: 10,
|
22
|
+
end: 19
|
23
|
+
}
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe Liquor::Error do
|
29
|
+
it "is an error" do
|
30
|
+
diag = Liquor::Error.new("foobar")
|
31
|
+
diag.error?.should be_true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Liquor::Deprecation do
|
36
|
+
it "is not an error" do
|
37
|
+
diag = Liquor::Deprecation.new("foobar")
|
38
|
+
diag.error?.should be_false
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Liquor::External do
|
4
|
+
it "should export methods" do
|
5
|
+
klass = Class.new do
|
6
|
+
include Liquor::External
|
7
|
+
|
8
|
+
def yes(param)
|
9
|
+
"result #{param}"
|
10
|
+
end
|
11
|
+
export :yes
|
12
|
+
|
13
|
+
def no
|
14
|
+
"not accessible"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
klass.should respond_to(:liquor_exports)
|
19
|
+
klass.liquor_exports.should == Set[:yes]
|
20
|
+
|
21
|
+
obj = klass.new
|
22
|
+
obj.liquor_send(:yes, 1).should == "result 1"
|
23
|
+
expect { obj.liquor_send(:no) }.to raise_error
|
24
|
+
expect { obj.liquor_send("yes", 1) }.not_to raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should correctly support inheritance" do
|
28
|
+
klass = Class.new do
|
29
|
+
include Liquor::External
|
30
|
+
|
31
|
+
def first
|
32
|
+
end
|
33
|
+
export :first
|
34
|
+
end
|
35
|
+
|
36
|
+
klass2 = Class.new(klass) do
|
37
|
+
def second
|
38
|
+
end
|
39
|
+
|
40
|
+
def third
|
41
|
+
end
|
42
|
+
|
43
|
+
export :second, :third
|
44
|
+
end
|
45
|
+
|
46
|
+
klass.liquor_exports.should == Set[:first]
|
47
|
+
klass2.liquor_exports.should == Set[:first, :second, :third]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be callable" do
|
51
|
+
klass = Class.new do
|
52
|
+
include Liquor::External
|
53
|
+
|
54
|
+
def static
|
55
|
+
"hello"
|
56
|
+
end
|
57
|
+
|
58
|
+
def dynamic(var)
|
59
|
+
"#{var} world"
|
60
|
+
end
|
61
|
+
|
62
|
+
def other
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def with_hash(param, options={})
|
67
|
+
"#{param} #{options.map{ |k,v| "#{k}: #{v}" }.join(" ")}"
|
68
|
+
end
|
69
|
+
|
70
|
+
export :static, :dynamic, :other, :with_hash
|
71
|
+
end
|
72
|
+
|
73
|
+
instance = klass.new
|
74
|
+
|
75
|
+
exec(%Q|{{ ext.static }}|, ext: instance).should == 'hello'
|
76
|
+
exec(%Q|{{ ext.other.static }}|, ext: instance).should == 'hello'
|
77
|
+
expect { exec(%Q|{{ ext.dynamic }}|, ext: instance) }.to raise_error
|
78
|
+
exec(%Q|{{ ext.dynamic() }}|, ext: instance).should == ' world'
|
79
|
+
exec(%Q|{{ ext.dynamic('bye') }}|, ext: instance).should == 'bye world'
|
80
|
+
exec(%Q|{{ ext.with_hash("1" two: "3") }}|, ext: instance).should == "1 two: 3"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should support indexing" do
|
84
|
+
klass = Class.new do
|
85
|
+
include Liquor::External
|
86
|
+
|
87
|
+
def [](index)
|
88
|
+
"element #{index}"
|
89
|
+
end
|
90
|
+
export :[]
|
91
|
+
end
|
92
|
+
|
93
|
+
instance = klass.new
|
94
|
+
|
95
|
+
exec(%Q|{{ ext[10] }}|, ext: instance).should == 'element 10'
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should wrap host errors" do
|
99
|
+
klass = Class.new do
|
100
|
+
include Liquor::External
|
101
|
+
|
102
|
+
def fail
|
103
|
+
Time.parse("nothing")
|
104
|
+
end
|
105
|
+
export :fail
|
106
|
+
end
|
107
|
+
|
108
|
+
instance = klass.new
|
109
|
+
|
110
|
+
expect {
|
111
|
+
exec(%Q|{{ ext.fail }}|, ext: instance)
|
112
|
+
}.to raise_error(Liquor::HostError)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should index chained externals" do
|
116
|
+
klass = Class.new do
|
117
|
+
include Liquor::External
|
118
|
+
|
119
|
+
def other
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
123
|
+
def [](index)
|
124
|
+
index
|
125
|
+
end
|
126
|
+
|
127
|
+
export :other, :[]
|
128
|
+
end
|
129
|
+
|
130
|
+
instance = klass.new
|
131
|
+
|
132
|
+
exec(%Q|{{ ext.other[5] }}|, ext: instance).should == '5'
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should correctly pass arrays" do
|
136
|
+
klass = Class.new do
|
137
|
+
include Liquor::External
|
138
|
+
|
139
|
+
attr_reader :memorized
|
140
|
+
|
141
|
+
def memorize(arg)
|
142
|
+
@memorized = arg
|
143
|
+
"d'oh"
|
144
|
+
end
|
145
|
+
|
146
|
+
export :memorize
|
147
|
+
end
|
148
|
+
|
149
|
+
instance = klass.new
|
150
|
+
|
151
|
+
expect {
|
152
|
+
exec(%Q|{{ ext.memorize(["a", "b"]) }}|, ext: instance)
|
153
|
+
}.not_to raise_error
|
154
|
+
|
155
|
+
instance.memorized.should == ["a", "b"]
|
156
|
+
end
|
157
|
+
|
158
|
+
it "concatenates indexable externals with tuples" do
|
159
|
+
klass = Class.new do
|
160
|
+
include Liquor::External
|
161
|
+
|
162
|
+
def initialize(array)
|
163
|
+
@array = array
|
164
|
+
end
|
165
|
+
|
166
|
+
def [](index); @array[index]; end
|
167
|
+
def size; @array.size; end
|
168
|
+
def to_a; @array; end
|
169
|
+
|
170
|
+
export :[], :size
|
171
|
+
end
|
172
|
+
|
173
|
+
exec(%Q|{% for i in: ext + ["b", "c"] do: %}{{ i }} {% end for %}|,
|
174
|
+
ext: klass.new(["0", "a"])).strip.should == "0 a b c"
|
175
|
+
end
|
176
|
+
|
177
|
+
it "sets up deprecations" do
|
178
|
+
klass = Class.new do
|
179
|
+
include Liquor::External
|
180
|
+
end
|
181
|
+
|
182
|
+
expect {
|
183
|
+
klass.class_eval { deprecate :foo }
|
184
|
+
}.to raise_error(ArgumentError)
|
185
|
+
|
186
|
+
expect {
|
187
|
+
klass.class_eval { deprecate :foo, date: '2012-03-14' }
|
188
|
+
}.to raise_error(ArgumentError)
|
189
|
+
|
190
|
+
expect {
|
191
|
+
klass.class_eval { deprecate :foo, message: 'not available' }
|
192
|
+
}.to raise_error(ArgumentError)
|
193
|
+
|
194
|
+
expect {
|
195
|
+
klass.class_eval { deprecate :foo, date: '2012-03-14', message: 'not available', foo: 'bar' }
|
196
|
+
}.to raise_error(ArgumentError)
|
197
|
+
|
198
|
+
klass.class_eval {
|
199
|
+
deprecate :foo, :bar, date: '2012-03-14', message: 'not available'
|
200
|
+
}
|
201
|
+
|
202
|
+
klass.liquor_deprecations.should == {
|
203
|
+
foo: { date: Date.parse('2012-03-14'), message: 'not available' },
|
204
|
+
bar: { date: Date.parse('2012-03-14'), message: 'not available' }
|
205
|
+
}
|
206
|
+
end
|
207
|
+
end
|