• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 9409557472

07 Jun 2024 12:09AM UTC coverage: 69.448% (-4.5%) from 73.988%
9409557472

push

github

alerque
fix(build): Distribute vendored compat-5.3.c source file

12025 of 17315 relevant lines covered (69.45%)

6023.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.32
/types/measurement.lua
1
--- SILE measurement type.
2
-- Measurements consist of an amount and a unit. Any registered `types.unit` may be used. Some units are relative and
3
-- their value may depend on the context where they are evaluated. Others are absolute. Unlike `types.length`
4
-- measurements have no stretch or shrink parameters.
5
-- @types measurement
6

7
local function _tonumber (amount)
8
   return SU.cast("number", amount)
37,418✔
9
end
10

11
local function _similarunit (a, b)
12
   if type(b) == "number" or type(a) == "number" then
156,411✔
13
      return true
13,375✔
14
   else
15
      return a.unit == b.unit
143,036✔
16
   end
17
end
18

19
local function _hardnumber (a, b)
20
   if type(b) == "number" or type(a) == "number" then
11,443✔
21
      return true
10,211✔
22
   else
23
      return false
1,232✔
24
   end
25
end
26

27
local function _unit (a, b)
28
   return type(a) == "table" and a.unit or b.unit
148,756✔
29
end
30

31
local function _amount (input)
32
   return type(input) == "number" and input or input.amount
298,698✔
33
end
34

35
local function _pt_amount (input)
36
   return type(input) == "number" and input or not input and 0 or input._mutable and input.amount or input:tonumber()
220,155✔
37
end
38

39
local function _error_if_immutable (input)
40
   if type(input) == "table" and not input._mutable then
218,741✔
41
      SU.error("Not so fast, we can't do mutating arithmetic except on 'pt' unit measurements!", true)
×
42
   end
43
end
44

45
local function _error_if_relative (a, b)
46
   if type(a) == "table" and a.relative or type(b) == "table" and b.relative then
18,505✔
47
      SU.error("Cannot do arithmetic on a relative measurement without explicitly absolutizing it.", true)
×
48
   end
49
end
50

51
--- @type measurement
52
local measurement = pl.class()
156✔
53
measurement.type = "measurement"
156✔
54

55
measurement.amount = 0
156✔
56
measurement.unit = "pt"
156✔
57
measurement.relative = false
156✔
58
measurement._mutable = false
156✔
59

60
--- Constructor.
61
-- @tparam number|length|measurement|string amount Amount of units or a string with the amount and unit.
62
-- @tparam[opt=pt] string unit Name of unit.
63
-- @treturn measurement
64
-- @usage
65
-- SILE.types.measurement(3, "em")
66
-- SILE.types.measurement("2%fw")
67
-- SILE.types.measurement(6)
68
function measurement:_init (amount, unit)
156✔
69
   if unit then
945,331✔
70
      self.unit = unit
149,509✔
71
   end
72
   if SU.type(amount) == "length" then
1,890,662✔
73
      self.amount = amount.length.amount
16✔
74
      self.unit = amount.length.unit
16✔
75
   elseif type(amount) == "table" then
945,315✔
76
      self.amount = amount.amount
176,423✔
77
      self.unit = amount.unit
176,423✔
78
   elseif type(tonumber(amount)) == "number" then
768,892✔
79
      self.amount = tonumber(amount)
360,697✔
80
   elseif type(amount) == "string" then
408,195✔
81
      local parsed = SILE.parserBits.measurement:match(amount)
230✔
82
      if not parsed then
230✔
83
         SU.error("Could not parse measurement '" .. amount .. "'")
×
84
      end
85
      self.amount, self.unit = parsed.amount, parsed.unit
230✔
86
   end
87
   local _su = SILE.types.unit[self.unit]
945,487✔
88
   if not _su then
945,331✔
89
      SU.error("Unknown unit: " .. unit)
×
90
   end
91
   self.relative = _su.relative
945,331✔
92
   if self.unit == "pt" then
945,331✔
93
      self._mutable = true
941,378✔
94
   end
95
end
96

97
--- Convert relative measurements to absolute values and return a measurement.
98
-- Resolves relative measurements (like em relevant to the current font size) into absolute measurements.
99
-- @treturn measurement A new measurement in pt with any relative values resolved.
100
-- @usage
101
-- > a = SILE.types.measurement("1.2em")
102
-- > print(a:absolute())
103
-- 12pt
104
function measurement:absolute ()
156✔
105
   return SILE.types.measurement(self:tonumber())
4,408✔
106
end
107

108
function measurement:tostring ()
156✔
109
   return self:__tostring()
×
110
end
111

112
--- Convert relative measurements to absolute values and return a number.
113
-- Similar to `measurement:absolute` but returns a number instead of a new measurement type.
114
-- @treturn number A number (corresponding to pts) for the amount with any relative values resolved.
115
function measurement:tonumber ()
156✔
116
   local def = SILE.types.unit[self.unit]
355,206✔
117
   local amount = def.converter and def.converter(self.amount) or (self.amount * def.value)
359,814✔
118
   return amount
355,206✔
119
end
120

121
function measurement:__tostring ()
156✔
122
   return self.amount .. self.unit
60✔
123
end
124

125
function measurement:__concat (other)
156✔
126
   return tostring(self) .. tostring(other)
44✔
127
end
128

129
--- Addition meta-method.
130
-- Assuming matching relative units or absolute units, allows two measurements to be combined into one.
131
-- @tparam measurement other
132
-- @treturn measuremnet A new measurement of the same unit type as `self` with the value of `other` added.
133
-- @usage
134
-- > a = SILE.types.measurement(6, "em")
135
-- > b = SILE.types.measurement("2em")
136
-- > c = a + b
137
-- > print(c)
138
-- 8em
139
function measurement:__add (other)
156✔
140
   if _similarunit(self, other) then
157,352✔
141
      return SILE.types.measurement(_amount(self) + _amount(other), _unit(self, other))
314,384✔
142
   else
143
      _error_if_relative(self, other)
80✔
144
      return SILE.types.measurement(_tonumber(self) + _tonumber(other))
240✔
145
   end
146
end
147

148
-- Note all private math (_ + __func()) functions:
149
-- * Are much faster than regular math operations
150
-- * Are **not** intended for use outside of the most performance sensitive loops
151
-- * Modify the lhs input in-place, never instantiating new objects
152
-- * Always assume absolute lhs input and absolutize the rhs values at runtime
153
-- * Assmue the inputs are sane with much less error checking than regular math funcs
154
-- * Are not composable using chained methods since they return nil for safety
155
function measurement:___add (other)
156✔
156
   _error_if_immutable(self)
205,370✔
157
   self.amount = self.amount + _pt_amount(other)
410,740✔
158
   return nil
205,370✔
159
end
160

161
function measurement:__sub (other)
156✔
162
   if _similarunit(self, other) then
155,470✔
163
      return SILE.types.measurement(_amount(self) - _amount(other), _unit(self, other))
242,168✔
164
   else
165
      _error_if_relative(self, other)
17,193✔
166
      return SILE.types.measurement(_tonumber(self) - _tonumber(other))
51,579✔
167
   end
168
end
169

170
-- See usage comments on SILE.types.measurement:___add()
171
function measurement:___sub (other)
156✔
172
   _error_if_immutable(self)
13,371✔
173
   self.amount = self.amount - _pt_amount(other)
26,742✔
174
   return nil
13,371✔
175
end
176

177
function measurement:__mul (other)
156✔
178
   if _hardnumber(self, other) then
19,240✔
179
      return SILE.types.measurement(_amount(self) * _amount(other), _unit(self, other))
38,472✔
180
   else
181
      _error_if_relative(self, other)
2✔
182
      return SILE.types.measurement(_tonumber(self) * _tonumber(other))
6✔
183
   end
184
end
185

186
function measurement:__pow (other)
156✔
187
   if _hardnumber(self, other) then
×
188
      return SILE.types.measurement(_amount(self) ^ _amount(other), self.unit)
×
189
   else
190
      _error_if_relative(self, other)
×
191
      return SILE.types.measurement(_tonumber(self) ^ _tonumber(other))
×
192
   end
193
end
194

195
function measurement:__div (other)
156✔
196
   if _hardnumber(self, other) then
3,576✔
197
      return SILE.types.measurement(_amount(self) / _amount(other), self.unit)
1,779✔
198
   else
199
      _error_if_relative(self, other)
1,195✔
200
      return SILE.types.measurement(_tonumber(self) / _tonumber(other))
3,585✔
201
   end
202
end
203

204
function measurement:__mod (other)
156✔
205
   if _hardnumber(self, other) then
70✔
206
      return SILE.types.measurement(_amount(self) % _amount(other), self.unit)
×
207
   else
208
      _error_if_relative(self, other)
35✔
209
      return SILE.types.measurement(_tonumber(self) % _tonumber(other))
105✔
210
   end
211
end
212

213
function measurement:__unm ()
156✔
214
   local ret = SILE.types.measurement(self)
77✔
215
   ret.amount = self.amount * -1
77✔
216
   return ret
77✔
217
end
218

219
function measurement:__eq (other)
156✔
220
   return _tonumber(self) == _tonumber(other)
63✔
221
end
222

223
function measurement:__lt (other)
156✔
224
   return _tonumber(self) < _tonumber(other)
549✔
225
end
226

227
function measurement:__le (other)
156✔
228
   return _tonumber(self) <= _tonumber(other)
×
229
end
230

231
return measurement
156✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc