/
value.cr
116 lines (99 loc) · 3.26 KB
/
value.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
module Marten
module Template
# A template value.
class Value
include Comparable(self)
include Enumerable(self)
alias Raw = Array(Value) | Bool | Float64 | Hash(Value, Value) | Int32 | Int64 | Iterator(Value) |
Marten::DB::Field::Any | Marten::DB::Model | Marten::Schema | Marten::Schema::BoundField |
Marten::Schema::Field::Base | Marten::Template::Object | Nil | SafeString |
String | Time | Handlers::Base | Emailing::Email
# Returns the raw value associated with the template value.
getter raw
def self.from(raw)
case raw
when Hash, NamedTuple
new(Hash(Value, Value).new.tap { |values| raw.each { |k, v| values[new(k.to_s)] = from(v) } })
when Array, Tuple
new(raw.map { |item| from(item).as(Value) }.to_a)
when Range
from(raw.to_a)
when Char
new(raw.to_s)
when Raw
new(raw)
when Value
raw
else
raise Errors::UnsupportedValue.new("Unable to initialize template values from #{raw.class} objects")
end
end
def initialize(@raw : Raw)
end
def [](key : String) : Value
self.class.from(resolve_attribute(key))
end
def ==(other : Value)
@raw == other.raw
end
def ==(other)
@raw == other
end
def <=>(other : Value)
raw_value = raw
other_value = other.raw
if raw_value.is_a?(Number) && other_value.is_a?(Number)
raw_value <=> other_value
else
raise Errors::UnsupportedType.new("Unable to compare #{raw.class} objects with #{other_value.class} objects")
end
end
def each(&)
yield_each_from_raw { |r| yield Value.from(r) }
end
# Returns `true` if the value is empty.
def empty?
if (object = raw).responds_to?(:empty?)
return object.empty?
end
false
end
# :nodoc:
def to_s(io)
@raw.to_s(io)
end
# Returns `true` if the value is truthy (ie. if it is not `false`, `0`, or `nil`).
def truthy?
!(@raw == false || @raw == 0 || @raw.nil?)
end
private def resolve_attribute(key)
object = raw
if object.responds_to?(:[]) && !object.is_a?(Array) && !object.is_a?(String) &&
!object.is_a?(Marten::Template::Object)
begin
return object[key.to_s]
rescue KeyError
end
elsif object.is_a?(Indexable) && !object.is_a?(Marten::Template::Object) && key.responds_to?(:to_i)
begin
return object[key.to_i]
rescue ArgumentError | IndexError
end
elsif object.responds_to?(:resolve_template_attribute)
return object.resolve_template_attribute(key.to_s)
end
raise Errors::UnknownVariable.new
end
private def yield_each_from_raw(&)
case object = raw
when Enumerable(Value), Iterable(Value)
object.each { |v| yield v.as(Value).raw }
when Enumerable, Iterable
object.each { |v| yield v }
else
raise Errors::UnsupportedType.new("#{object.class} objects are not iterable")
end
end
end
end
end