Introduce abstract generic value type

Sits between AbstractExpression and Value and Block.
This commit is contained in:
Michael Miller 2021-01-15 22:32:02 -07:00
parent 4ed8c4a573
commit a74957204b
No known key found for this signature in database
GPG key ID: FB9F12F7C646A4AD
5 changed files with 46 additions and 22 deletions

View file

@ -6,25 +6,30 @@ module Spectator
# It consists of a label and the value of the expression.
# The label should be a string recognizable by the user,
# or nil if one isn't available.
#
# This base class is provided so that all generic sub-classes can be stored as this one type.
# The value of the expression can be retrieved by downcasting to the expected type with `#cast`.
#
# NOTE: This is intentionally a class and not a struct.
# If it were a struct, changes made to the value held by an instance may not be kept when passing it around.
# See commit ca564619ad2ae45f832a058d514298c868fdf699.
abstract class AbstractExpression
# User recognizable string for the expression.
# This can be something like a variable name or a snippet of Crystal code.
getter label : Label
# Creates the expression.
# The *label* is usually the Crystal code evaluating to the `#value`.
# The *label* is usually the Crystal code evaluating to the `#raw_value`.
# It can be nil if it isn't available.
def initialize(@label : Label)
end
# Retrieves the real value of the expression.
abstract def value
# Retrieves the evaluated value of the expression.
abstract def raw_value
# Attempts to cast `#value` to the type *T* and return it.
# Attempts to cast `#raw_value` to the type *T* and return it.
def cast(type : T.class) : T forall T
value.as(T)
raw_value.as(T)
end
# Produces a string representation of the expression.
@ -35,7 +40,7 @@ module Spectator
io << ':'
io << ' '
end
io << value
raw_value.to_s(io)
end
# Produces a detailed string representation of the expression.
@ -46,7 +51,7 @@ module Spectator
io << ':'
io << ' '
end
value.inspect(io)
raw_value.inspect(io)
end
end
end

View file

@ -1,4 +1,4 @@
require "./abstract_expression"
require "./expression"
require "./label"
require "./lazy"
@ -8,7 +8,7 @@ module Spectator
# It consists of a label and parameterless block.
# The label should be a string recognizable by the user,
# or nil if one isn't available.
class Block(T) < AbstractExpression
class Block(T) < Expression(T)
# Cached value returned from the block.
@value = Lazy(T).new

View file

@ -1,7 +1,8 @@
require "../assertion"
require "../assertion_failed"
require "../expression"
require "../block"
require "../source"
require "../value"
module Spectator::DSL
# Methods and macros for asserting that conditions are met.
@ -50,7 +51,7 @@ module Spectator::DSL
{{actual}}
end
%expression = ::Spectator::Expression.new(%actual, {{actual.stringify}})
%expression = ::Spectator::Value.new(%actual, {{actual.stringify}})
%source = ::Spectator::Source.new({{actual.filename}}, {{actual.line_number}})
::Spectator::Assertion::Target.new(%expression, %source)
end

View file

@ -1,22 +1,18 @@
require "./abstract_expression"
require "./label"
module Spectator
# Represents an expression from a test.
# This is typically captured by an `expect` macro.
# It consists of a label and the value of the expression.
# It consists of a label and a typed expression.
# The label should be a string recognizable by the user,
# or nil if one isn't available.
class Expression(T) < AbstractExpression
# Raw value of the expression.
getter value
abstract class Expression(T) < AbstractExpression
# Retrieves the underlying value of the expression.
abstract def value : T
# Creates the expression.
# Expects the *value* of the expression and a *label* describing it.
# The *label* is usually the Crystal code evaluating to the *value*.
# It can be nil if it isn't available.
def initialize(@value : T, label : Label)
super(label)
# Retrieves the evaluated value of the expression.
def raw_value
value
end
end
end

22
src/spectator/value.cr Normal file
View file

@ -0,0 +1,22 @@
require "./expression"
require "./label"
module Spectator
# Represents a value from a test.
# This is typically captured by an `expect` macro.
# It consists of a label and the value of the expression.
# The label should be a string recognizable by the user,
# or nil if one isn't available.
class Value(T) < Expression(T)
# Raw value of the expression.
getter value : T
# Creates the value.
# Expects the *value* of the expression and a *label* describing it.
# The *label* is usually the Crystal code evaluating to the *value*.
# It can be nil if it isn't available.
def initialize(@value : T, label : Label)
super(label)
end
end
end