lesslateral 1.2.21
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.
- data/.gitignore +4 -0
- data/CHANGELOG +62 -0
- data/LICENSE +179 -0
- data/README.md +48 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/bin/lessc +103 -0
- data/less.gemspec +134 -0
- data/lib/less.rb +36 -0
- data/lib/less/command.rb +108 -0
- data/lib/less/engine.rb +52 -0
- data/lib/less/engine/grammar/common.tt +29 -0
- data/lib/less/engine/grammar/entity.tt +144 -0
- data/lib/less/engine/grammar/less.tt +341 -0
- data/lib/less/engine/nodes.rb +9 -0
- data/lib/less/engine/nodes/element.rb +281 -0
- data/lib/less/engine/nodes/entity.rb +79 -0
- data/lib/less/engine/nodes/function.rb +93 -0
- data/lib/less/engine/nodes/literal.rb +171 -0
- data/lib/less/engine/nodes/property.rb +232 -0
- data/lib/less/engine/nodes/ruleset.rb +12 -0
- data/lib/less/engine/nodes/selector.rb +44 -0
- data/lib/less/ext.rb +60 -0
- data/lib/less/notification.rb +59 -0
- data/spec/command_spec.rb +102 -0
- data/spec/css/accessors.css +18 -0
- data/spec/css/big.css +3768 -0
- data/spec/css/colors.css +14 -0
- data/spec/css/comments.css +9 -0
- data/spec/css/css-3.css +21 -0
- data/spec/css/css.css +50 -0
- data/spec/css/dash-prefix.css +12 -0
- data/spec/css/functions.css +6 -0
- data/spec/css/import-with-extra-paths.css +8 -0
- data/spec/css/import-with-partial-in-extra-path.css +6 -0
- data/spec/css/import.css +12 -0
- data/spec/css/lazy-eval.css +1 -0
- data/spec/css/mixins-args.css +32 -0
- data/spec/css/mixins.css +28 -0
- data/spec/css/operations.css +28 -0
- data/spec/css/parens.css +20 -0
- data/spec/css/rulesets.css +17 -0
- data/spec/css/scope.css +11 -0
- data/spec/css/selectors.css +13 -0
- data/spec/css/strings.css +12 -0
- data/spec/css/variables.css +8 -0
- data/spec/css/whitespace.css +7 -0
- data/spec/engine_spec.rb +127 -0
- data/spec/less/accessors.less +20 -0
- data/spec/less/big.less +1264 -0
- data/spec/less/colors.less +35 -0
- data/spec/less/comments.less +46 -0
- data/spec/less/css-3.less +52 -0
- data/spec/less/css.less +104 -0
- data/spec/less/dash-prefix.less +21 -0
- data/spec/less/exceptions/mixed-units-error.less +3 -0
- data/spec/less/exceptions/name-error-1.0.less +3 -0
- data/spec/less/exceptions/syntax-error-1.0.less +3 -0
- data/spec/less/extra_import_path/extra.less +1 -0
- data/spec/less/extra_import_path/import/import-test-a.css +1 -0
- data/spec/less/extra_import_path/import/import-test-a.less +4 -0
- data/spec/less/functions.less +6 -0
- data/spec/less/hidden.less +25 -0
- data/spec/less/import-with-extra-paths.less +4 -0
- data/spec/less/import.less +8 -0
- data/spec/less/import/import-test-a.less +2 -0
- data/spec/less/import/import-test-b.less +8 -0
- data/spec/less/import/import-test-c.less +7 -0
- data/spec/less/import/import-test-d.css +1 -0
- data/spec/less/lazy-eval.less +6 -0
- data/spec/less/literal-css.less +11 -0
- data/spec/less/mixins-args.less +59 -0
- data/spec/less/mixins.less +43 -0
- data/spec/less/operations.less +39 -0
- data/spec/less/parens.less +26 -0
- data/spec/less/rulesets.less +30 -0
- data/spec/less/scope.less +32 -0
- data/spec/less/selectors.less +24 -0
- data/spec/less/strings.less +14 -0
- data/spec/less/variables.less +29 -0
- data/spec/less/whitespace.less +34 -0
- data/spec/spec.css +50 -0
- data/spec/spec_helper.rb +8 -0
- metadata +159 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
module Less
|
2
|
+
#
|
3
|
+
# Node::Entity
|
4
|
+
#
|
5
|
+
# Everything in the tree is an Entity
|
6
|
+
#
|
7
|
+
# Mixin/Class hierarchy
|
8
|
+
#
|
9
|
+
# - Entity
|
10
|
+
# - Element
|
11
|
+
# - Entity
|
12
|
+
# - Function
|
13
|
+
# - Keyword
|
14
|
+
# - Literal
|
15
|
+
# - Color
|
16
|
+
# - Number
|
17
|
+
# - String
|
18
|
+
# - FontFamily
|
19
|
+
# - Property
|
20
|
+
# - Variable
|
21
|
+
#
|
22
|
+
# TODO: Use delegate class -> @rules
|
23
|
+
#
|
24
|
+
module Node
|
25
|
+
module Entity
|
26
|
+
attr_accessor :parent
|
27
|
+
|
28
|
+
def initialize value, parent = nil
|
29
|
+
super value
|
30
|
+
@parent = parent
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Returns the path from any given node, to the root
|
35
|
+
#
|
36
|
+
# ex: ['color', 'p', '#header', 'body', '*']
|
37
|
+
#
|
38
|
+
def path node = self
|
39
|
+
path = []
|
40
|
+
while node do
|
41
|
+
path << node
|
42
|
+
node = node.parent
|
43
|
+
end
|
44
|
+
path
|
45
|
+
end
|
46
|
+
|
47
|
+
def root
|
48
|
+
path.last
|
49
|
+
end
|
50
|
+
|
51
|
+
def inspect; to_s end
|
52
|
+
def to_css; to_s end
|
53
|
+
def to_s; super end
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# An anonymous node, for all the 'other' stuff
|
58
|
+
# which doesn't need any specific functionality.
|
59
|
+
#
|
60
|
+
class Anonymous < String
|
61
|
+
include Entity
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# + * - /
|
66
|
+
#
|
67
|
+
class Operator < String
|
68
|
+
def to_ruby
|
69
|
+
self
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Paren < String
|
74
|
+
def to_ruby
|
75
|
+
self
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Less
|
2
|
+
#
|
3
|
+
# Functions useable from within the style-sheet go here
|
4
|
+
#
|
5
|
+
module Functions
|
6
|
+
def rgb *rgb
|
7
|
+
rgba rgb, 1.0
|
8
|
+
end
|
9
|
+
|
10
|
+
def hsl *args
|
11
|
+
hsla *[args, 1.0].flatten
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# RGBA to Node::Color
|
16
|
+
#
|
17
|
+
def rgba *rgba
|
18
|
+
Node::Color.new *rgba.flatten
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# HSLA to RGBA
|
23
|
+
#
|
24
|
+
def hsla h, s, l, a = 1.0
|
25
|
+
m2 = ( l <= 0.5 ) ? l * ( s + 1 ) : l + s - l * s
|
26
|
+
m1 = l * 2 - m2;
|
27
|
+
|
28
|
+
hue = lambda do |h|
|
29
|
+
h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h)
|
30
|
+
if h * 6 < 1 then m1 + (m2 - m1) * h * 6
|
31
|
+
elsif h * 2 < 1 then m2
|
32
|
+
elsif h * 3 < 2 then m1 + (m2 - m1) * (2/3 - h) * 6
|
33
|
+
else m1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
rgba hue[ h + 1/3 ], hue[ h ], hue[ h - 1/3 ], a
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.available
|
41
|
+
self.instance_methods.map(&:to_sym)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module Node
|
46
|
+
#
|
47
|
+
# A CSS function, like rgb() or url()
|
48
|
+
#
|
49
|
+
# it calls functions from the Functions module
|
50
|
+
#
|
51
|
+
class Function < String
|
52
|
+
include Entity
|
53
|
+
include Functions
|
54
|
+
|
55
|
+
def initialize name, args
|
56
|
+
@args = if args.is_a? Array
|
57
|
+
args.map {|e| e.is_a?(Expression) ? e : Expression.new(e, self)}
|
58
|
+
else
|
59
|
+
[args]
|
60
|
+
end
|
61
|
+
|
62
|
+
super name
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_css env = nil
|
66
|
+
self.evaluate(env).to_css
|
67
|
+
end
|
68
|
+
|
69
|
+
def nearest node
|
70
|
+
parent.nearest node
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Call the function
|
75
|
+
#
|
76
|
+
# If the function isn't found, we just print it out,
|
77
|
+
# this is the case for url(), for example,
|
78
|
+
#
|
79
|
+
def evaluate context = nil
|
80
|
+
if Functions.available.include? self.to_sym
|
81
|
+
send to_sym, *@args
|
82
|
+
else
|
83
|
+
args = @args.map { |e|
|
84
|
+
e.parent = self.parent
|
85
|
+
e = e.evaluate(context) if e.respond_to?(:evaluate)
|
86
|
+
e.to_css
|
87
|
+
} * ', '
|
88
|
+
Node::Anonymous.new("#{to_sym}(#{args})")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module Less
|
2
|
+
module Node
|
3
|
+
module Literal
|
4
|
+
include Entity
|
5
|
+
|
6
|
+
def unit
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# rgb(255, 0, 0) #f0f0f0
|
13
|
+
#
|
14
|
+
class Color
|
15
|
+
include Literal
|
16
|
+
attr_reader :r, :g, :b, :a
|
17
|
+
|
18
|
+
def initialize r, g, b, a = 1.0
|
19
|
+
@r, @g, @b = [r, g, b].map do |c|
|
20
|
+
normalize(c.is_a?(String) ? c.to_i(16) : c)
|
21
|
+
end
|
22
|
+
@a = normalize(a, 1.0)
|
23
|
+
end
|
24
|
+
|
25
|
+
def alpha v
|
26
|
+
self.class.new r, g, b, v
|
27
|
+
end
|
28
|
+
|
29
|
+
def rgb
|
30
|
+
[r, g, b]
|
31
|
+
end
|
32
|
+
|
33
|
+
def operate op, other
|
34
|
+
color = if other.is_a? Numeric
|
35
|
+
rgb.map {|c| c.send(op, other) }
|
36
|
+
else
|
37
|
+
rgb.zip(other.rgb).map {|a, b| a.send(op, b) }
|
38
|
+
end
|
39
|
+
self.class.new *[color, @a].flatten # Ruby 1.8 hack
|
40
|
+
end
|
41
|
+
|
42
|
+
def + other; operate :+, other end
|
43
|
+
def - other; operate :-, other end
|
44
|
+
def * other; operate :*, other end
|
45
|
+
def / other; operate :/, other end
|
46
|
+
|
47
|
+
def coerce other
|
48
|
+
return self, other
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
if a < 1.0
|
53
|
+
"rgba(#{r.to_i}, #{g.to_i}, #{b.to_i}, #{a})"
|
54
|
+
else
|
55
|
+
"#%02x%02x%02x" % [r, g, b]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def inspect
|
60
|
+
if a < 1.0
|
61
|
+
"rgba(#{r}, #{g}, #{b}, #{a})"
|
62
|
+
else
|
63
|
+
"rgb(#{r}, #{g}, #{b})"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_css
|
68
|
+
to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_ruby
|
72
|
+
"#{self.class}.new(#{r},#{g},#{b},#{a})"
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
def normalize(v, max = 255, min = 0)
|
77
|
+
[[min, v].max, max].min
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# 6 10px 125%
|
83
|
+
#
|
84
|
+
class Number < DelegateClass(Float)
|
85
|
+
include Literal
|
86
|
+
|
87
|
+
attr_accessor :unit
|
88
|
+
|
89
|
+
def initialize value, unit = nil
|
90
|
+
super value.to_f
|
91
|
+
@unit = (unit.nil? || unit.empty?) ? nil : unit
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_s
|
95
|
+
"#{super}#@unit"
|
96
|
+
end
|
97
|
+
|
98
|
+
def dup
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_ruby
|
103
|
+
self.to_f
|
104
|
+
end
|
105
|
+
|
106
|
+
def inspect
|
107
|
+
to_s
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_css
|
111
|
+
"#{(self % 1).zero?? "#{self.to_i}#@unit" : self}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
#
|
116
|
+
# "hello world"
|
117
|
+
#
|
118
|
+
class Quoted < String
|
119
|
+
include Literal
|
120
|
+
|
121
|
+
attr_reader :quotes, :content
|
122
|
+
|
123
|
+
# Strip quotes if necessary, and save them in @quotes
|
124
|
+
def initialize str
|
125
|
+
@quotes, @content = unless str.nil? or str.empty?
|
126
|
+
str.match(/('|")(.*?)(\1)/).captures rescue [nil, str]
|
127
|
+
else
|
128
|
+
[nil, ""]
|
129
|
+
end
|
130
|
+
super @content
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_css
|
134
|
+
"#@quotes#{@content}#@quotes"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class Font
|
139
|
+
include Literal
|
140
|
+
end
|
141
|
+
|
142
|
+
class FontFamily
|
143
|
+
include Literal
|
144
|
+
|
145
|
+
def initialize family = []
|
146
|
+
@family = family
|
147
|
+
end
|
148
|
+
|
149
|
+
def to_css
|
150
|
+
@family.map(&:to_css) * ', '
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# Any un-quoted word
|
156
|
+
#
|
157
|
+
# ex: red, small, border-collapse
|
158
|
+
#
|
159
|
+
class Keyword < String
|
160
|
+
include Entity
|
161
|
+
|
162
|
+
def to_css
|
163
|
+
self
|
164
|
+
end
|
165
|
+
|
166
|
+
def inspect
|
167
|
+
"#{self}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
module Less
|
2
|
+
module Node
|
3
|
+
class Property < String
|
4
|
+
include Entity
|
5
|
+
|
6
|
+
attr_accessor :value
|
7
|
+
|
8
|
+
def initialize key, value = nil, parent = nil
|
9
|
+
super key, parent
|
10
|
+
value = if value.is_a? Array
|
11
|
+
value.each {|v| v.parent = self if v.respond_to? :parent }.
|
12
|
+
map {|v| v.is_a?(Expression) ? v : Expression.new(v, self) }
|
13
|
+
elsif value.nil?
|
14
|
+
[]
|
15
|
+
else
|
16
|
+
value
|
17
|
+
end
|
18
|
+
@value = value.is_a?(Expression) ? value : Expression.new(value, self)
|
19
|
+
@value.parent = self
|
20
|
+
@value.delimiter = ','
|
21
|
+
# puts "new property #{to_s}: #{value} => #{@value}, contains: #{@value[0].class}"
|
22
|
+
# puts
|
23
|
+
end
|
24
|
+
|
25
|
+
def parent= obj
|
26
|
+
@parent = obj
|
27
|
+
value.parent = self
|
28
|
+
end
|
29
|
+
|
30
|
+
def copy
|
31
|
+
clone.tap {|c| c.value = value.copy }
|
32
|
+
end
|
33
|
+
|
34
|
+
def << token
|
35
|
+
token = Node::Anonymous.new(*token) unless token.is_a? Entity or token.respond_to? :to_ruby
|
36
|
+
token.parent = self if token.respond_to? :parent
|
37
|
+
@value << token
|
38
|
+
end
|
39
|
+
|
40
|
+
def empty?; !@value || @value.empty? end
|
41
|
+
|
42
|
+
def inspect
|
43
|
+
self + (empty?? "" : ": `#{value.map {|i| i.to_s } * ' | '}`")
|
44
|
+
end
|
45
|
+
|
46
|
+
def == other
|
47
|
+
self.to_s == other.to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
def eql? other
|
51
|
+
self == other and value.eql? other.value
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
def nearest node
|
59
|
+
parent.nearest node
|
60
|
+
end
|
61
|
+
|
62
|
+
def evaluate env = nil
|
63
|
+
# puts "evaluating property `#{to_s}`: #{value.inspect}"
|
64
|
+
if value.is_a?(Expression) #Value
|
65
|
+
# puts "value is a Value"
|
66
|
+
value.map {|e| e.evaluate(env) } #6
|
67
|
+
else
|
68
|
+
# puts "value is a #{value.class}"
|
69
|
+
[value.evaluate(env)]
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_css env = nil
|
76
|
+
# puts "property.to_css `#{to_s}` env:#{env ? env.variables : "nil"}"
|
77
|
+
val = evaluate(env)
|
78
|
+
"#{self}: #{if val.respond_to? :to_css
|
79
|
+
val.to_css
|
80
|
+
else
|
81
|
+
# p val
|
82
|
+
# puts "#{val.class} #{val.first.class}"
|
83
|
+
val.map {|i| i.to_css }.join(", ")
|
84
|
+
end};"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Variable < Property
|
89
|
+
attr_reader :declaration
|
90
|
+
|
91
|
+
def initialize key, value = nil, parent = nil
|
92
|
+
@declaration = value ? true : false
|
93
|
+
super key.delete('@'), value, parent
|
94
|
+
end
|
95
|
+
|
96
|
+
def inspect
|
97
|
+
"@#{super}"
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_s
|
101
|
+
"@#{super}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def evaluate env = nil
|
105
|
+
if declaration
|
106
|
+
# puts "evaluating DEC"
|
107
|
+
value.evaluate #2
|
108
|
+
else
|
109
|
+
# puts "evaluating #{to_s} par: #{parent} env: #{env ? env.variables : "nil"}"
|
110
|
+
begin
|
111
|
+
var = (env || self.parent).nearest(to_s) #3
|
112
|
+
rescue VariableNameError
|
113
|
+
var = self.parent.nearest(to_s)
|
114
|
+
end
|
115
|
+
var.evaluate
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_ruby
|
120
|
+
evaluate.to_ruby
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_css env = nil
|
124
|
+
val = evaluate env
|
125
|
+
if val.respond_to? :to_css
|
126
|
+
env ? val.to_css(env) : val.to_css
|
127
|
+
else
|
128
|
+
val.map {|i| env ? i.to_css(env) : i.to_css }.join ', '
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class Expression < Array
|
134
|
+
attr_accessor :parent, :delimiter
|
135
|
+
|
136
|
+
def initialize ary, parent = nil, delimiter = ' '
|
137
|
+
self.parent = parent
|
138
|
+
self.delimiter = delimiter
|
139
|
+
# puts "new expression #{ary} |#{delimiter}|"
|
140
|
+
super(ary.is_a?(Array) ? ary : [ary].flatten)
|
141
|
+
end
|
142
|
+
|
143
|
+
def expressions; select {|i| i.kind_of? Expression } end
|
144
|
+
def variables; select {|i| i.kind_of? Variable } end
|
145
|
+
def operators; select {|i| i.is_a? Operator } end
|
146
|
+
def entities; select {|i| i.kind_of? Entity } end
|
147
|
+
def literals; select {|i| i.kind_of? Literal } end
|
148
|
+
|
149
|
+
def parent= obj
|
150
|
+
@parent = obj
|
151
|
+
each {|e| e.parent = obj if e.respond_to? :parent }
|
152
|
+
end
|
153
|
+
|
154
|
+
def inspect
|
155
|
+
'[' + map {|i| i.inspect }.join(', ') + ']'
|
156
|
+
end
|
157
|
+
|
158
|
+
def delimiter= d
|
159
|
+
@delimiter = d.strip + ' '
|
160
|
+
end
|
161
|
+
|
162
|
+
def flatten
|
163
|
+
self
|
164
|
+
end
|
165
|
+
|
166
|
+
def terminal?
|
167
|
+
expressions.empty? #&& variables.empty?
|
168
|
+
end
|
169
|
+
|
170
|
+
def to_css env = nil
|
171
|
+
# puts "TOCSS, delim: |#{@delimiter}|"
|
172
|
+
map do |i|
|
173
|
+
i.parent = self.parent
|
174
|
+
i.respond_to?(:to_css) ? i.to_css() : i.to_s
|
175
|
+
end * @delimiter
|
176
|
+
end
|
177
|
+
|
178
|
+
def to_ruby
|
179
|
+
map do |i|
|
180
|
+
i.respond_to?(:to_ruby) ? i.to_ruby : i.to_s
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
#
|
185
|
+
# Evaluates the expression and instantiates a new Literal with the result
|
186
|
+
# ex: [#111, +, #111] will evaluate to a Color node, with value #222
|
187
|
+
#
|
188
|
+
def evaluate env = nil
|
189
|
+
# puts "expression #{self.inspect} env: #{env ? env.variables : "nil"}"
|
190
|
+
if size > 2 or !terminal?
|
191
|
+
# puts " SIZE > 2 or !terminal"
|
192
|
+
|
193
|
+
# puts "--- sub evaluation ---"
|
194
|
+
|
195
|
+
# Replace self with an evaluated sub-expression
|
196
|
+
evaled = self.class.new(map {|e| e.respond_to?(:evaluate) ? e.evaluate(env) : e }, parent, delimiter) #5
|
197
|
+
|
198
|
+
# puts "======================"
|
199
|
+
# puts "evaled => #{evaled.inspect}"
|
200
|
+
|
201
|
+
unit = evaled.literals.map do |node|
|
202
|
+
node.unit
|
203
|
+
end.compact.uniq.tap do |ary|
|
204
|
+
raise MixedUnitsError, evaled * ' ' if ary.size > 1 && !evaled.operators.empty?
|
205
|
+
end.join
|
206
|
+
|
207
|
+
entity = evaled.literals.find {|e| e.unit == unit } || evaled.literals.first || evaled.entities.first
|
208
|
+
result = evaled.operators.empty?? evaled : eval(evaled.to_ruby.join)
|
209
|
+
|
210
|
+
# puts "entity is a #{entity.class}"
|
211
|
+
# puts "delimiter is |#{@delimiter}|"
|
212
|
+
|
213
|
+
case result
|
214
|
+
when Entity then result
|
215
|
+
when Expression then result.one?? result.first : self.class.new(result, parent, delimiter)
|
216
|
+
else entity.class.new(result, *(unit if entity.class == Node::Number))
|
217
|
+
end
|
218
|
+
elsif size == 1
|
219
|
+
if first.is_a? Variable
|
220
|
+
first.evaluate(env)
|
221
|
+
elsif first.is_a? Function
|
222
|
+
first.evaluate(env)
|
223
|
+
else
|
224
|
+
first
|
225
|
+
end
|
226
|
+
else
|
227
|
+
self
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|