diff --git a/src/spectator/abstract_expression.cr b/src/spectator/abstract_expression.cr index 2a58e06..3bb20f2 100644 --- a/src/spectator/abstract_expression.cr +++ b/src/spectator/abstract_expression.cr @@ -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 diff --git a/src/spectator/block.cr b/src/spectator/block.cr index 312681a..5deb82c 100644 --- a/src/spectator/block.cr +++ b/src/spectator/block.cr @@ -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 diff --git a/src/spectator/dsl/assertions.cr b/src/spectator/dsl/assertions.cr index 791ad73..d868d16 100644 --- a/src/spectator/dsl/assertions.cr +++ b/src/spectator/dsl/assertions.cr @@ -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 diff --git a/src/spectator/expression.cr b/src/spectator/expression.cr index b12efce..0937b8e 100644 --- a/src/spectator/expression.cr +++ b/src/spectator/expression.cr @@ -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 diff --git a/src/spectator/value.cr b/src/spectator/value.cr new file mode 100644 index 0000000..9d04871 --- /dev/null +++ b/src/spectator/value.cr @@ -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