Skip to content

Commit

Permalink
Ensure custom template objects always raise UnknownVariable exception…
Browse files Browse the repository at this point in the history
…s when attributes cannot be resolved
  • Loading branch information
ellmetha committed Jul 22, 2024
1 parent de40933 commit 34c5517
Show file tree
Hide file tree
Showing 18 changed files with 119 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ describe Marten::Template::CanDefineTemplateAttributes do
test = Marten::Template::CanDefineTemplateAttributesSpec::Test.new
test.resolve_template_attribute("foo").should eq "foo"
test.resolve_template_attribute("bar").should eq "bar"
test.resolve_template_attribute("xyz").should be_nil
end

it "raises a Marten::Template::Errors::UnknownVariable exception when the attribute is not defined" do
test = Marten::Template::CanDefineTemplateAttributesSpec::Test.new
expect_raises(Marten::Template::Errors::UnknownVariable) do
test.resolve_template_attribute("xyz")
end
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions spec/marten/template/ext/marten/db/fields/file/file_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,14 @@ describe Marten::DB::Field::File::File do

file.resolve_template_attribute("url").should eq field.storage.url("css/app.css")
end

it "raises as expected if the specified attribute is not supported" do
field = Marten::DB::Field::File.new("my_field")
file = Marten::DB::Field::File::File.new(field, "path/to/file.txt")

expect_raises(Marten::Template::Errors::UnknownVariable) do
file.resolve_template_attribute("unknown_attribute")
end
end
end
end
9 changes: 9 additions & 0 deletions spec/marten/template/ext/marten/db/query/page_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,14 @@ describe Marten::DB::Query::Page do
Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("size").should eq 1
Marten::DB::Query::Page(Tag).new([] of Tag, 2, paginator).resolve_template_attribute("size").should eq 0
end

it "raises as expected if the specified attribute is not supported" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)

expect_raises(Marten::Template::Errors::UnknownVariable) do
Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("unknown")
end
end
end
end
8 changes: 8 additions & 0 deletions spec/marten/template/ext/marten/db/query/paginator_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,13 @@ describe Marten::DB::Query::Paginator do

paginator.resolve_template_attribute("pages_count").should eq 3
end

it "raises as expected if the specified attribute is not supported" do
paginator = Tag.all.order(:name).paginator(2)

expect_raises(Marten::Template::Errors::UnknownVariable) do
paginator.resolve_template_attribute("unknown_attribute")
end
end
end
end
6 changes: 6 additions & 0 deletions spec/marten/template/ext/marten/db/query/set_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,11 @@ describe Marten::DB::Query::Set do

Tag.all.resolve_template_attribute("size").should eq 2
end

it "raises as expected if the specified attribute is not supported" do
expect_raises(Marten::Template::Errors::UnknownVariable) do
Tag.all.resolve_template_attribute("unknown")
end
end
end
end
6 changes: 4 additions & 2 deletions spec/marten/template/ext/marten/http/flash_store_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ describe Marten::HTTP::FlashStore do
flash_store.resolve_template_attribute("alert").should eq "bad"
end

it "returns nil if the flash message is not found" do
it "raises as expected if the specified attribute is not supported" do
flash_store = Marten::HTTP::FlashStore.new(flashes: {"foo" => "bar", "alert" => "bad"}, discard: [] of String)

flash_store.resolve_template_attribute("unknown").should be_nil
expect_raises(Marten::Template::Errors::UnknownVariable) do
flash_store.resolve_template_attribute("unknown")
end
end
end
end
6 changes: 4 additions & 2 deletions spec/marten/template/ext/marten/schema/bound_field_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ describe Marten::Schema::BoundField do
bound_field_2.resolve_template_attribute("value").should be_nil
end

it "returns nil if the passed attribute name is not found" do
it "raises as expected if the passed attribute is not supported" do
schema = Marten::Schema::BoundFieldExtSpec::TestSchema.new(Marten::HTTP::Params::Data{"foo" => ["hello"]})
bound_field = Marten::Schema::BoundField.new(schema, schema.class.get_field("foo"))

bound_field.resolve_template_attribute("unknown").should be_nil
expect_raises(Marten::Template::Errors::UnknownVariable) do
bound_field.resolve_template_attribute("unknown")
end
end
end
end
Expand Down
6 changes: 4 additions & 2 deletions spec/marten/template/ext/marten/schema_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ describe Marten::Schema do
errors.should eq schema.errors
end

it "returns nil if the passed attribute name is not found" do
it "raises as expected if the passed attribute name is not found" do
schema = Marten::SchemaExtSpec::SimpleSchema.new(Marten::HTTP::Params::Data{"foo" => ["hello"]})

schema.resolve_template_attribute("unknown").should be_nil
expect_raises(Marten::Template::Errors::UnknownVariable) do
schema.resolve_template_attribute("unknown")
end
end
end
end
Expand Down
33 changes: 24 additions & 9 deletions spec/marten/template/object/auto_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,49 @@ describe Marten::Template::Object::Auto do
obj.resolve_template_attribute("attr").should eq "hello"
end

it "allows to resolve a key using the #[]? method as a fallback" do
it "allows to resolve a key using the #[] method as a fallback" do
obj = Marten::Template::Object::AutoSpec::Test.new({"foo" => "bar"})
obj.resolve_template_attribute("foo").should eq "bar"
end

it "does not resolve the value using the #[]? method if a public method is resolved first" do
it "resolves values #[] with priority over a method with the same key" do
obj = Marten::Template::Object::AutoSpec::Test.new({"attr" => "bar"})
obj.resolve_template_attribute("attr").should eq "hello"
obj.resolve_template_attribute("attr").should eq "bar"
end

it "does not allow to resolve a method that takes arguments" do
obj = Marten::Template::Object::AutoSpec::Test.new
obj.resolve_template_attribute("with_args").should be_nil
expect_raises(Marten::Template::Errors::UnknownVariable) do
obj.resolve_template_attribute("with_args")
end
end

it "does not allow to resolve a method that takes a block" do
obj = Marten::Template::Object::AutoSpec::Test.new
obj.resolve_template_attribute("with_block").should be_nil
expect_raises(Marten::Template::Errors::UnknownVariable) do
obj.resolve_template_attribute("with_block")
end
end

it "does not allow to resolve a protected method" do
obj = Marten::Template::Object::AutoSpec::Test.new
obj.resolve_template_attribute("protected_attr").should be_nil
expect_raises(Marten::Template::Errors::UnknownVariable) do
obj.resolve_template_attribute("protected_attr")
end
end

it "does not allow to resolve a private method" do
obj = Marten::Template::Object::AutoSpec::Test.new
obj.resolve_template_attribute("private_attr").should be_nil
expect_raises(Marten::Template::Errors::UnknownVariable) do
obj.resolve_template_attribute("private_attr")
end
end

it "raises a Marten::Template::Errors::UnknownVariable exception if the attribute is not supported" do
obj = Marten::Template::Object::AutoSpec::Test.new
expect_raises(Marten::Template::Errors::UnknownVariable) do
obj.resolve_template_attribute("unknown")
end
end
end
end
Expand All @@ -46,8 +61,8 @@ module Marten::Template::Object::AutoSpec
def initialize(@data = {} of String => String)
end

def []?(key : String)
@data[key]?
def [](key : String)
@data[key]
end

def attr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ module Marten
when {% if name.is_a?(StringLiteral) %}{{ name }}{% else %}{{ name.id.stringify }}{% end %}
{{ name.id }}
{% end %}
else
raise Marten::Template::Errors::UnknownVariable.new
end
end
end
Expand Down
14 changes: 1 addition & 13 deletions src/marten/template/ext/marten/db/field/file/file.cr
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
class Marten::DB::Field::File::File
include Marten::Template::Object

# :nodoc:
def resolve_template_attribute(key : ::String)
case key
when "attached?"
attached?
when "name"
name
when "size"
size
when "url"
url
end
end
template_attributes :attached?, :name, :size, :url
end
32 changes: 2 additions & 30 deletions src/marten/template/ext/marten/db/query/page.cr
Original file line number Diff line number Diff line change
@@ -1,34 +1,6 @@
class Marten::DB::Query::Page(M)
include Marten::Template::Object

def resolve_template_attribute(key : String)
case key
when "all?"
all?
when "any?"
any?
when "count"
count
when "empty?"
empty?
when "first?"
first?
when "next_page?"
next_page?
when "next_page_number"
next_page_number
when "none?"
none?
when "number"
number
when "one?"
one?
when "previous_page?"
previous_page?
when "previous_page_number"
previous_page_number
when "size"
size
end
end
template_attributes :all?, :any?, :count, :empty?, :first?, :next_page?, :next_page_number, :none?, :number, :one?,
:previous_page?, :previous_page_number, :size
end
9 changes: 1 addition & 8 deletions src/marten/template/ext/marten/db/query/paginator.cr
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
class Marten::DB::Query::Paginator(M)
include Marten::Template::Object

def resolve_template_attribute(key : String)
case key
when "page_size"
page_size
when "pages_count"
pages_count
end
end
template_attributes :page_size, :pages_count
end
40 changes: 2 additions & 38 deletions src/marten/template/ext/marten/db/query/set.cr
Original file line number Diff line number Diff line change
@@ -1,42 +1,6 @@
class Marten::DB::Query::Set(M)
include Marten::Template::Object

def resolve_template_attribute(key : String)
case key
when "all"
all
when "all?"
all?
when "any?"
any?
when "count"
count
when "distinct"
distinct
when "empty?"
empty?
when "exists?"
exists?
when "first"
first
when "first!"
first!
when "first?"
first?
when "last"
last
when "last!"
last!
when "none"
none
when "none?"
none?
when "one?"
one?
when "reverse"
reverse
when "size"
size
end
end
template_attributes :all, :all?, :any?, :count, :distinct, :empty?, :exists?, :first, :first!, :first?, :last, :last!,
:none, :none?, :one?, :reverse, :size
end
4 changes: 3 additions & 1 deletion src/marten/template/ext/marten/http/flash_store.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ class Marten::HTTP::FlashStore
when "size"
size
else
self[key]?
self[key]
end
rescue KeyError
raise Marten::Template::Errors::UnknownVariable.new
end
end
4 changes: 3 additions & 1 deletion src/marten/template/ext/marten/schema.cr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ abstract class Marten::Schema
when "errors"
errors
else
self[key]?
self[key]
end
rescue Marten::Schema::Errors::UnknownField
raise Marten::Template::Errors::UnknownVariable.new
end
end
2 changes: 2 additions & 0 deletions src/marten/template/ext/marten/schema/bound_field.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class Marten::Schema::BoundField
id
when "value"
value
else
raise Marten::Template::Errors::UnknownVariable.new
end
end
end
44 changes: 28 additions & 16 deletions src/marten/template/object/auto.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,39 @@ module Marten
# :nodoc:
def resolve_template_attribute(key : String)
{% begin %}
value = case key
{% if !@type.abstract? && !@type.type_vars.any?(&.abstract?) %}
{% already_processed = [] of String %}
{% for type in [@type] + @type.ancestors %}
{% if type.name != "Object" && type.name != "Reference" %}
{% for method in type.methods %}
{% if !already_processed.includes?(method.name.id.stringify) %}
{% if method.visibility == :public && !method.accepts_block? && method.args.empty? %}
when {{ method.name.id.stringify }}
self.{{ method.name.id }}
{% already_processed << method.name.id.stringify %}
value = nil
looked_up_value = false

if responds_to?(:[])
begin
value = self[key]
looked_up_value = true
rescue KeyError
# Do nothing
end
end

if !looked_up_value
value = case key
{% if !@type.abstract? && !@type.type_vars.any?(&.abstract?) %}
{% already_processed = [] of String %}
{% for type in [@type] + @type.ancestors %}
{% if type.name != "Object" && type.name != "Reference" %}
{% for method in type.methods %}
{% if !already_processed.includes?(method.name.id.stringify) %}
{% if method.visibility == :public && !method.accepts_block? && method.args.empty? %}
when {{ method.name.id.stringify }}
self.{{ method.name.id }}
{% already_processed << method.name.id.stringify %}
{% end %}
{% end %}
{% end %}
{% end %}
{% end %}
{% end %}
{% end %}
end

if value.nil? && responds_to?(:[]?)
value = self[key]?
else
raise Marten::Template::Errors::UnknownVariable.new
end
end

value
Expand Down

0 comments on commit 34c5517

Please sign in to comment.