morpher 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of morpher might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.circle.yml +6 -0
- data/.gitignore +5 -0
- data/.rspec +4 -0
- data/.rubocop.yml +8 -0
- data/Changelog.md +60 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +56 -0
- data/Rakefile +95 -0
- data/circle.yml +7 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/heckle.yml +3 -0
- data/config/mutant.yml +8 -0
- data/config/reek.yml +109 -0
- data/config/rubocop.yml +138 -0
- data/config/yardstick.yml +2 -0
- data/examples/README.md +13 -0
- data/examples/a.rb +25 -0
- data/examples/b.rb +35 -0
- data/lib/morpher.rb +111 -0
- data/lib/morpher/compiler.rb +17 -0
- data/lib/morpher/compiler/emitter.rb +82 -0
- data/lib/morpher/compiler/error.rb +84 -0
- data/lib/morpher/compiler/evaluator.rb +63 -0
- data/lib/morpher/compiler/evaluator/emitter.rb +224 -0
- data/lib/morpher/compiler/preprocessor.rb +29 -0
- data/lib/morpher/compiler/preprocessor/emitter.rb +54 -0
- data/lib/morpher/compiler/preprocessor/emitter/anima.rb +69 -0
- data/lib/morpher/compiler/preprocessor/emitter/boolean.rb +31 -0
- data/lib/morpher/compiler/preprocessor/emitter/key.rb +87 -0
- data/lib/morpher/compiler/preprocessor/emitter/noop.rb +45 -0
- data/lib/morpher/compiler/preprocessor/emitter/param.rb +50 -0
- data/lib/morpher/evaluation.rb +118 -0
- data/lib/morpher/evaluator.rb +40 -0
- data/lib/morpher/evaluator/binary.rb +46 -0
- data/lib/morpher/evaluator/nary.rb +97 -0
- data/lib/morpher/evaluator/nullary.rb +92 -0
- data/lib/morpher/evaluator/nullary/parameterized.rb +48 -0
- data/lib/morpher/evaluator/predicate.rb +22 -0
- data/lib/morpher/evaluator/predicate/boolean.rb +76 -0
- data/lib/morpher/evaluator/predicate/contradiction.rb +36 -0
- data/lib/morpher/evaluator/predicate/eql.rb +50 -0
- data/lib/morpher/evaluator/predicate/negation.rb +52 -0
- data/lib/morpher/evaluator/predicate/primitive.rb +49 -0
- data/lib/morpher/evaluator/predicate/tautology.rb +36 -0
- data/lib/morpher/evaluator/transformer.rb +75 -0
- data/lib/morpher/evaluator/transformer/attribute.rb +25 -0
- data/lib/morpher/evaluator/transformer/block.rb +81 -0
- data/lib/morpher/evaluator/transformer/coerce.rb +166 -0
- data/lib/morpher/evaluator/transformer/custom.rb +34 -0
- data/lib/morpher/evaluator/transformer/domain.rb +86 -0
- data/lib/morpher/evaluator/transformer/domain/attribute_accessors.rb +60 -0
- data/lib/morpher/evaluator/transformer/domain/attribute_hash.rb +52 -0
- data/lib/morpher/evaluator/transformer/domain/instance_variables.rb +60 -0
- data/lib/morpher/evaluator/transformer/domain/param.rb +54 -0
- data/lib/morpher/evaluator/transformer/guard.rb +62 -0
- data/lib/morpher/evaluator/transformer/hash_transform.rb +149 -0
- data/lib/morpher/evaluator/transformer/input.rb +37 -0
- data/lib/morpher/evaluator/transformer/key.rb +86 -0
- data/lib/morpher/evaluator/transformer/map.rb +100 -0
- data/lib/morpher/evaluator/transformer/merge.rb +25 -0
- data/lib/morpher/evaluator/transformer/static.rb +27 -0
- data/lib/morpher/evaluator/unary.rb +79 -0
- data/lib/morpher/node_helpers.rb +19 -0
- data/lib/morpher/printer.rb +233 -0
- data/lib/morpher/printer/mixin.rb +58 -0
- data/lib/morpher/registry.rb +51 -0
- data/lib/morpher/type_lookup.rb +51 -0
- data/morpher.gemspec +29 -0
- data/spec/integration_spec.rb +184 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/evaluator_behavior.rb +155 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/support/ice_nine_config.rb +8 -0
- data/spec/support/let_mock_helper.rb +8 -0
- data/spec/support/strip_helper.rb +12 -0
- data/spec/unit/morpher/compiler/preprocessor_spec.rb +46 -0
- data/spec/unit/morpher/evaluator/nullary/parameterized_spec.rb +25 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/and_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/or_spec.rb +26 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/xor_spec.rb +26 -0
- data/spec/unit/morpher/evaluator/predicate/contrandiction_spec.rb +7 -0
- data/spec/unit/morpher/evaluator/predicate/eql_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/predicate/negation_spec.rb +10 -0
- data/spec/unit/morpher/evaluator/predicate/primitive_spec.rb +17 -0
- data/spec/unit/morpher/evaluator/predicate/tautology_spec.rb +7 -0
- data/spec/unit/morpher/evaluator/transformer/attribute_spec.rb +9 -0
- data/spec/unit/morpher/evaluator/transformer/block_spec.rb +92 -0
- data/spec/unit/morpher/evaluator/transformer/coerce/parse_int_spec.rb +23 -0
- data/spec/unit/morpher/evaluator/transformer/custom_spec.rb +13 -0
- data/spec/unit/morpher/evaluator/transformer/domain/attribute_accessors_spec.rb +48 -0
- data/spec/unit/morpher/evaluator/transformer/domain/attribute_hash_spec.rb +40 -0
- data/spec/unit/morpher/evaluator/transformer/domain/instance_variables_spec.rb +47 -0
- data/spec/unit/morpher/evaluator/transformer/guard_spec.rb +12 -0
- data/spec/unit/morpher/evaluator/transformer/hash_transform_spec.rb +47 -0
- data/spec/unit/morpher/evaluator/transformer/input_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/transformer/map_spec.rb +25 -0
- data/spec/unit/morpher/evaluator/transformer/static_spec.rb +10 -0
- data/spec/unit/morpher/evaluator_spec.rb +15 -0
- data/spec/unit/morpher/printer_spec.rb +21 -0
- data/spec/unit/morpher/registry_spec.rb +11 -0
- data/spec/unit/morpher_spec.rb +53 -0
- metadata +302 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
|
5
|
+
# Identity transformer which always returns +input+
|
6
|
+
class Input < self
|
7
|
+
include Nullary, Transitive
|
8
|
+
|
9
|
+
register :input
|
10
|
+
|
11
|
+
# Call evaluator with input
|
12
|
+
#
|
13
|
+
# @param [Object] input
|
14
|
+
#
|
15
|
+
# @return [Object]
|
16
|
+
# always returns input
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
def call(input)
|
21
|
+
input
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return inverse evaluator
|
25
|
+
#
|
26
|
+
# @return [Evaluator::Transformer]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
def inverse
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
end # Input
|
35
|
+
end # Transformer
|
36
|
+
end # Evaluator
|
37
|
+
end # Morpher
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
# Abstract namespace class for evaluators operating on hash keys
|
5
|
+
class Key < self
|
6
|
+
include AbstractType, Nullary::Parameterized, Intransitive
|
7
|
+
|
8
|
+
# Evaluator for dumping hash keys
|
9
|
+
class Dump < self
|
10
|
+
|
11
|
+
register :key_dump
|
12
|
+
|
13
|
+
# Call evaluator
|
14
|
+
#
|
15
|
+
# @param [Object] object
|
16
|
+
#
|
17
|
+
# @return [Array]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
def call(object)
|
22
|
+
[param, object]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return inverse evaluator
|
26
|
+
#
|
27
|
+
# @return [Fetch]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
#
|
31
|
+
def inverse
|
32
|
+
Fetch.new(param)
|
33
|
+
end
|
34
|
+
|
35
|
+
end # Dump
|
36
|
+
|
37
|
+
# Evaluator to fetch a specific hash key
|
38
|
+
class Fetch < self
|
39
|
+
|
40
|
+
register :key_fetch
|
41
|
+
|
42
|
+
# Call evaluator
|
43
|
+
#
|
44
|
+
# @param [Hash] object
|
45
|
+
#
|
46
|
+
# @return [Object]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
#
|
50
|
+
def call(object)
|
51
|
+
object.fetch(param) do
|
52
|
+
fail TransformError.new(self, object)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return evaluation
|
57
|
+
#
|
58
|
+
# @param [Object] input
|
59
|
+
#
|
60
|
+
# @return [Evaluation]
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
#
|
64
|
+
def evaluation(input)
|
65
|
+
output = input.fetch(param) do
|
66
|
+
return evaluation_error(input)
|
67
|
+
end
|
68
|
+
|
69
|
+
evaluation_success(input, output)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Return inverse evaluator
|
73
|
+
#
|
74
|
+
# @return [Dump]
|
75
|
+
#
|
76
|
+
# @api private
|
77
|
+
#
|
78
|
+
def inverse
|
79
|
+
Dump.new(param)
|
80
|
+
end
|
81
|
+
|
82
|
+
end # Fetch
|
83
|
+
end # Key
|
84
|
+
end # Transformer
|
85
|
+
end # Evaluator
|
86
|
+
end # Morpher
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
|
5
|
+
# Transformer over each element in an enumerable
|
6
|
+
class Map < self
|
7
|
+
include Unary
|
8
|
+
|
9
|
+
register :map
|
10
|
+
|
11
|
+
# Test if evaluator is transitive
|
12
|
+
#
|
13
|
+
# @return [true]
|
14
|
+
# if evaluator is transitive
|
15
|
+
#
|
16
|
+
# @return [false]
|
17
|
+
# otherwise
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
def transitive?
|
22
|
+
operand.transitive?
|
23
|
+
end
|
24
|
+
|
25
|
+
# Call evaluator
|
26
|
+
#
|
27
|
+
# @param [Enumerable#map] input
|
28
|
+
#
|
29
|
+
# @return [Enumerable]
|
30
|
+
# if input evaluates true under predicate
|
31
|
+
#
|
32
|
+
# @raise [TransformError]
|
33
|
+
# otherwise
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
def call(input)
|
38
|
+
input.map(&operand.method(:call))
|
39
|
+
end
|
40
|
+
|
41
|
+
# Return evaluation
|
42
|
+
#
|
43
|
+
# @param [Enumerable#map] input
|
44
|
+
#
|
45
|
+
# @return [Evaluation]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
# rubocop:disable MethodLength
|
50
|
+
#
|
51
|
+
def evaluation(input)
|
52
|
+
evaluations = input.each_with_object([]) do |item, aggregate|
|
53
|
+
evaluation = operand.evaluation(item)
|
54
|
+
aggregate << evaluation
|
55
|
+
unless evaluation.success?
|
56
|
+
return evaluation_error(input, aggregate)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Evaluation::Nary.success(
|
61
|
+
evaluator: self,
|
62
|
+
input: input,
|
63
|
+
output: evaluations.map(&:output),
|
64
|
+
evaluations: evaluations
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return inverse evaluator
|
69
|
+
#
|
70
|
+
# @return [Evaluator::Transformer]
|
71
|
+
#
|
72
|
+
# @api private
|
73
|
+
#
|
74
|
+
def inverse
|
75
|
+
self.class.new(operand.inverse)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# Return evaluation error
|
81
|
+
#
|
82
|
+
# @param [Object] input
|
83
|
+
# @param [Array<Evaluation>] evaluations
|
84
|
+
#
|
85
|
+
# @return [Evaluation]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
#
|
89
|
+
def evaluation_error(input, evaluations)
|
90
|
+
Evaluation::Nary.error(
|
91
|
+
evaluator: self,
|
92
|
+
input: input,
|
93
|
+
evaluations: evaluations
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
end # Guard
|
98
|
+
end # Transformer
|
99
|
+
end # Evaluator
|
100
|
+
end # Morpher
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
# Transformer to merge input into defaults
|
5
|
+
class Merge < self
|
6
|
+
include Intransitive, Nullary::Parameterized
|
7
|
+
|
8
|
+
register :merge
|
9
|
+
|
10
|
+
# Call evaluator for input
|
11
|
+
#
|
12
|
+
# @param [Object] input
|
13
|
+
#
|
14
|
+
# @return [Object] output
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def call(input)
|
19
|
+
param.merge(input)
|
20
|
+
end
|
21
|
+
|
22
|
+
end # Merge
|
23
|
+
end # Transformer
|
24
|
+
end # Evaluator
|
25
|
+
end # Morpher
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
|
5
|
+
# Transformer that always returns the passed +param+
|
6
|
+
class Static < self
|
7
|
+
include Nullary::Parameterized, Intransitive
|
8
|
+
|
9
|
+
register :static
|
10
|
+
|
11
|
+
# Call evaluator with input
|
12
|
+
#
|
13
|
+
# @param [Object] _input
|
14
|
+
#
|
15
|
+
# @return [Object]
|
16
|
+
# alwasys returns the param
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
def call(_input)
|
21
|
+
param
|
22
|
+
end
|
23
|
+
|
24
|
+
end # Static
|
25
|
+
end # Transformer
|
26
|
+
end # Evaluator
|
27
|
+
end # Morpher
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
|
4
|
+
# Mixin for unary evaluators
|
5
|
+
module Unary
|
6
|
+
CONCORD = Concord::Public.new(:operand)
|
7
|
+
|
8
|
+
PRINTER = lambda do |_|
|
9
|
+
name
|
10
|
+
indent do
|
11
|
+
visit(:operand)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return node
|
16
|
+
#
|
17
|
+
# @return [AST::Node]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
def node
|
22
|
+
s(type, operand.node)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Return success evaluation for input
|
28
|
+
#
|
29
|
+
# @param [Object] input
|
30
|
+
#
|
31
|
+
# @return [Evalation::Unary]
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
def evaluation_success(input, operand_evaluation, output)
|
36
|
+
Evaluation::Unary.success(
|
37
|
+
evaluator: self,
|
38
|
+
input: input,
|
39
|
+
operand_evaluation: operand_evaluation,
|
40
|
+
output: output
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return error evaluation for input
|
45
|
+
#
|
46
|
+
# @param [Object] input
|
47
|
+
#
|
48
|
+
# @return [Evalation::Unary]
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
#
|
52
|
+
def evaluation_error(input, operand_evaluation)
|
53
|
+
Evaluation::Unary.error(
|
54
|
+
evaluator: self,
|
55
|
+
input: input,
|
56
|
+
operand_evaluation: operand_evaluation
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Hook called when module gets included
|
63
|
+
#
|
64
|
+
# @return [undefined]
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
#
|
68
|
+
def self.included(descendant)
|
69
|
+
descendant.class_eval do
|
70
|
+
include CONCORD
|
71
|
+
printer(&PRINTER)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
private_class_method :included
|
75
|
+
|
76
|
+
end # Unary
|
77
|
+
|
78
|
+
end # Evaluator
|
79
|
+
end # Morpher
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Morpher
|
2
|
+
# Node helpers
|
3
|
+
module NodeHelpers
|
4
|
+
|
5
|
+
# Build node
|
6
|
+
#
|
7
|
+
# @param [Symbol] type
|
8
|
+
#
|
9
|
+
# @return [Parser::AST::Node]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
def s(type, *children)
|
14
|
+
AST::Node.new(type, children)
|
15
|
+
end
|
16
|
+
module_function :s
|
17
|
+
|
18
|
+
end # NodeHelpers
|
19
|
+
end # Morpher
|
@@ -0,0 +1,233 @@
|
|
1
|
+
module Morpher
|
2
|
+
|
3
|
+
# Evaluation and Evaluator pretty printer
|
4
|
+
class Printer
|
5
|
+
include Adamantium::Flat, Concord.new(:object, :output, :indent_level)
|
6
|
+
|
7
|
+
INDENT = ' '.freeze
|
8
|
+
|
9
|
+
REGISTRY = {}
|
10
|
+
|
11
|
+
# Run pretty printer on object
|
12
|
+
#
|
13
|
+
# @param [Object] object
|
14
|
+
# the object to be pretty printed
|
15
|
+
# @param [IO] output
|
16
|
+
# the output to write to
|
17
|
+
# @param [Fixnum] indent_level
|
18
|
+
# the current indentation level
|
19
|
+
#
|
20
|
+
# @return [self]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
def self.run(object, output, indent_level = 0)
|
25
|
+
printer = new(object, output, indent_level)
|
26
|
+
block = lookup(object)
|
27
|
+
printer.instance_eval(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Perform type lookup
|
31
|
+
#
|
32
|
+
# FIXME: Instanciate type lookup once and allow caching.
|
33
|
+
#
|
34
|
+
# @param [Evaluation, Evaluator] object
|
35
|
+
#
|
36
|
+
# @return [Proc]
|
37
|
+
# if found
|
38
|
+
#
|
39
|
+
# @raise [PrinterMissingException]
|
40
|
+
# otherwise
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
def self.lookup(object)
|
45
|
+
TypeLookup.new(REGISTRY).call(object)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Visit a child
|
51
|
+
#
|
52
|
+
# @param [Node] child
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
#
|
56
|
+
# @return [undefined]
|
57
|
+
#
|
58
|
+
def visit_child(child)
|
59
|
+
self.class.run(child, output, indent_level.succ)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Visit a child by name
|
63
|
+
#
|
64
|
+
# @param [Symbol] name
|
65
|
+
# the attribute name of the child to visit
|
66
|
+
#
|
67
|
+
# @return [undefined]
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
#
|
71
|
+
def visit(name)
|
72
|
+
child = object.public_send(name)
|
73
|
+
child_label(name)
|
74
|
+
visit_child(child)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Visit many children
|
78
|
+
#
|
79
|
+
# @param [Symbol] name
|
80
|
+
# the name of the collection attribute with children to visit
|
81
|
+
#
|
82
|
+
# @return [undefined]
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
#
|
86
|
+
def visit_many(name)
|
87
|
+
children = object.public_send(name)
|
88
|
+
child_label(name)
|
89
|
+
children.each do |child|
|
90
|
+
visit_child(child)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Print attribute class
|
95
|
+
#
|
96
|
+
# @param [Symbol] name
|
97
|
+
#
|
98
|
+
# @return [undefined]
|
99
|
+
#
|
100
|
+
# @api private
|
101
|
+
#
|
102
|
+
def attribute_class(name)
|
103
|
+
label_value(name, object.public_send(name).class)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Print inspected attribute value with label
|
107
|
+
#
|
108
|
+
# @return [undefined]
|
109
|
+
#
|
110
|
+
# @api private
|
111
|
+
#
|
112
|
+
def attribute(name)
|
113
|
+
label_value(name, object.public_send(name))
|
114
|
+
end
|
115
|
+
|
116
|
+
# Print attributes of object
|
117
|
+
#
|
118
|
+
# @return [undefined]
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
#
|
122
|
+
def attributes(*names)
|
123
|
+
names.each do |name|
|
124
|
+
attribute(name)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Print name of object
|
129
|
+
#
|
130
|
+
# @return [undefined]
|
131
|
+
#
|
132
|
+
# @api private
|
133
|
+
#
|
134
|
+
def name
|
135
|
+
puts(object.class.name)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Return string indented with current level
|
139
|
+
#
|
140
|
+
# @param [String] content
|
141
|
+
#
|
142
|
+
# @return [String]
|
143
|
+
#
|
144
|
+
# @api private
|
145
|
+
#
|
146
|
+
def indented(content)
|
147
|
+
"#{indentation_prefix}#{content}"
|
148
|
+
end
|
149
|
+
|
150
|
+
# Return indentation prefix
|
151
|
+
#
|
152
|
+
# @return [String]
|
153
|
+
#
|
154
|
+
# @api private
|
155
|
+
#
|
156
|
+
def indentation_prefix
|
157
|
+
INDENT * indent_level
|
158
|
+
end
|
159
|
+
memoize :indentation_prefix
|
160
|
+
|
161
|
+
# Add content to output at current indentation and close line
|
162
|
+
#
|
163
|
+
# @param [String] content
|
164
|
+
#
|
165
|
+
# @return [undefined]
|
166
|
+
#
|
167
|
+
# @api private
|
168
|
+
#
|
169
|
+
def puts(string)
|
170
|
+
output.puts(indented(string))
|
171
|
+
end
|
172
|
+
|
173
|
+
# Write content to output at current indentation
|
174
|
+
#
|
175
|
+
# @param [String] content
|
176
|
+
#
|
177
|
+
# @return [undefined]
|
178
|
+
#
|
179
|
+
# @api private
|
180
|
+
#
|
181
|
+
def write(string)
|
182
|
+
output.write(indented(string))
|
183
|
+
end
|
184
|
+
|
185
|
+
# Write child label to output at current indentation
|
186
|
+
#
|
187
|
+
# @param [String] label
|
188
|
+
#
|
189
|
+
# @return [undefined]
|
190
|
+
#
|
191
|
+
# @api private
|
192
|
+
#
|
193
|
+
def child_label(string)
|
194
|
+
puts("#{string}:")
|
195
|
+
end
|
196
|
+
|
197
|
+
# Call block inside indented context
|
198
|
+
#
|
199
|
+
# @return [undefined]
|
200
|
+
#
|
201
|
+
# @api private
|
202
|
+
#
|
203
|
+
def indent(&block)
|
204
|
+
printer = new(object, output, indent_level.succ)
|
205
|
+
printer.instance_eval(&block)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Return new printer
|
209
|
+
#
|
210
|
+
# @return [Printer]
|
211
|
+
#
|
212
|
+
# @api private
|
213
|
+
#
|
214
|
+
def new(*arguments)
|
215
|
+
self.class.new(*arguments)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Print label with value
|
219
|
+
#
|
220
|
+
# @param [String] label
|
221
|
+
# @param [Object] value
|
222
|
+
#
|
223
|
+
# @return [undefined]
|
224
|
+
#
|
225
|
+
# @api private
|
226
|
+
#
|
227
|
+
def label_value(label, value)
|
228
|
+
write("#{label}: ")
|
229
|
+
output.puts(value.inspect)
|
230
|
+
end
|
231
|
+
|
232
|
+
end # Printer
|
233
|
+
end # Morpher
|