nrser 0.0.26 → 0.0.27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nrser.rb +1 -0
- data/lib/nrser/array.rb +15 -0
- data/lib/nrser/binding.rb +7 -1
- data/lib/nrser/enumerable.rb +21 -1
- data/lib/nrser/errors.rb +56 -6
- data/lib/nrser/hash/deep_merge.rb +1 -1
- data/lib/nrser/message.rb +33 -0
- data/lib/nrser/meta/props.rb +77 -15
- data/lib/nrser/meta/props/prop.rb +276 -44
- data/lib/nrser/proc.rb +7 -3
- data/lib/nrser/refinements/array.rb +5 -0
- data/lib/nrser/refinements/enumerable.rb +5 -0
- data/lib/nrser/refinements/hash.rb +8 -0
- data/lib/nrser/refinements/object.rb +11 -1
- data/lib/nrser/refinements/string.rb +17 -3
- data/lib/nrser/refinements/symbol.rb +8 -0
- data/lib/nrser/refinements/tree.rb +22 -0
- data/lib/nrser/rspex.rb +312 -70
- data/lib/nrser/rspex/shared_examples.rb +116 -0
- data/lib/nrser/string.rb +159 -27
- data/lib/nrser/temp/unicode_math.rb +48 -0
- data/lib/nrser/text.rb +3 -0
- data/lib/nrser/text/indentation.rb +210 -0
- data/lib/nrser/text/lines.rb +52 -0
- data/lib/nrser/text/word_wrap.rb +29 -0
- data/lib/nrser/tree.rb +4 -78
- data/lib/nrser/tree/each_branch.rb +76 -0
- data/lib/nrser/tree/map_branches.rb +91 -0
- data/lib/nrser/tree/map_tree.rb +97 -0
- data/lib/nrser/tree/transform.rb +56 -13
- data/lib/nrser/types.rb +1 -0
- data/lib/nrser/types/array.rb +15 -3
- data/lib/nrser/types/is_a.rb +40 -1
- data/lib/nrser/types/nil.rb +17 -0
- data/lib/nrser/types/paths.rb +17 -2
- data/lib/nrser/types/strings.rb +57 -22
- data/lib/nrser/types/tuples.rb +5 -0
- data/lib/nrser/types/type.rb +47 -6
- data/lib/nrser/version.rb +1 -1
- data/spec/nrser/errors/abstract_method_error_spec.rb +46 -0
- data/spec/nrser/meta/props/to_and_from_data_spec.rb +74 -0
- data/spec/nrser/meta/props_spec.rb +6 -2
- data/spec/nrser/refinements/erb_spec.rb +100 -1
- data/spec/nrser/{common_prefix_spec.rb → string/common_prefix_spec.rb} +9 -0
- data/spec/nrser/text/dedent_spec.rb +80 -0
- data/spec/nrser/tree/map_branch_spec.rb +83 -0
- data/spec/nrser/tree/map_tree_spec.rb +123 -0
- data/spec/nrser/tree/transform_spec.rb +26 -29
- data/spec/nrser/tree/transformer_spec.rb +179 -0
- data/spec/nrser/types/paths_spec.rb +73 -45
- data/spec/spec_helper.rb +10 -0
- metadata +27 -7
- data/spec/nrser/dedent_spec.rb +0 -36
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
module NRSER
|
3
|
+
# @!group Text
|
4
|
+
|
5
|
+
# Classes
|
6
|
+
# =====================================================================
|
7
|
+
|
8
|
+
# @todo document Lines class.
|
9
|
+
class Lines < Array
|
10
|
+
|
11
|
+
# Constants
|
12
|
+
# ======================================================================
|
13
|
+
|
14
|
+
|
15
|
+
# Class Methods
|
16
|
+
# ======================================================================
|
17
|
+
|
18
|
+
|
19
|
+
# Attributes
|
20
|
+
# ======================================================================
|
21
|
+
|
22
|
+
|
23
|
+
# Constructor
|
24
|
+
# ======================================================================
|
25
|
+
|
26
|
+
# Instantiate a new `Lines`.
|
27
|
+
def initialize
|
28
|
+
|
29
|
+
end # #initialize
|
30
|
+
|
31
|
+
|
32
|
+
# Instance Methods
|
33
|
+
# ======================================================================
|
34
|
+
|
35
|
+
end # class Lines
|
36
|
+
|
37
|
+
|
38
|
+
# Functions
|
39
|
+
# =====================================================================
|
40
|
+
|
41
|
+
def self.lines text
|
42
|
+
case text
|
43
|
+
when String
|
44
|
+
text.lines
|
45
|
+
when Array
|
46
|
+
text
|
47
|
+
else
|
48
|
+
raise TypeError, "Expected String or Array, found #{ text.class.name }"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end # module NRSER
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
module NRSER
|
3
|
+
# @!group Text
|
4
|
+
|
5
|
+
# Split text at whitespace to fit in line length. Lifted from Rails'
|
6
|
+
# ActionView.
|
7
|
+
#
|
8
|
+
# @see http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-word_wrap
|
9
|
+
#
|
10
|
+
# @param [String] text
|
11
|
+
# Text to word wrap.
|
12
|
+
#
|
13
|
+
# @param [Fixnum] line_width:
|
14
|
+
# Line with in number of character to wrap at.
|
15
|
+
#
|
16
|
+
# @param [String] break_sequence:
|
17
|
+
# String to join lines with.
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
# @todo Document return value.
|
21
|
+
#
|
22
|
+
def self.word_wrap text, line_width: 80, break_sequence: "\n"
|
23
|
+
text.split("\n").collect! do |line|
|
24
|
+
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line
|
25
|
+
end * break_sequence
|
26
|
+
end # .word_wrap
|
27
|
+
|
28
|
+
|
29
|
+
end # module NRSER
|
data/lib/nrser/tree.rb
CHANGED
@@ -3,84 +3,10 @@
|
|
3
3
|
|
4
4
|
# Project / Package
|
5
5
|
# -----------------------------------------------------------------------
|
6
|
+
|
7
|
+
require_relative './tree/each_branch'
|
8
|
+
require_relative './tree/map_branches'
|
9
|
+
require_relative './tree/map_tree'
|
6
10
|
require_relative './tree/leaves'
|
7
11
|
require_relative './tree/map_leaves'
|
8
12
|
require_relative './tree/transform'
|
9
|
-
|
10
|
-
|
11
|
-
# Definitions
|
12
|
-
# =======================================================================
|
13
|
-
|
14
|
-
module NRSER
|
15
|
-
|
16
|
-
# Enumerate over the immediate "branches" of a structure that can be used
|
17
|
-
# to compose our idea of a *tree*: nested hash-like and array-like structures
|
18
|
-
# like you would get from parsing a JSON document.
|
19
|
-
#
|
20
|
-
# Written and tested against Hash and Array instances, but should work with
|
21
|
-
# anything hash-like that responds to `#each_pair` appropriately or
|
22
|
-
# array-like that responds to `#each_index` and `#each_with_index`.
|
23
|
-
#
|
24
|
-
# @note Not sure what will happen if the tree has circular references!
|
25
|
-
#
|
26
|
-
# @param [#each_pair | (#each_index & #each_with_index)] tree
|
27
|
-
# Structure representing a tree via hash-like and array-like containers.
|
28
|
-
#
|
29
|
-
# @yieldparam [Object] key
|
30
|
-
# The first yielded param is the key or index for the value branch at the
|
31
|
-
# top level of `tree`.
|
32
|
-
#
|
33
|
-
# @yieldparam [Object] value
|
34
|
-
# The second yielded param is the branch at the key or index at the top
|
35
|
-
# level of `tree`.
|
36
|
-
#
|
37
|
-
# @yieldreturn
|
38
|
-
# Ignored.
|
39
|
-
#
|
40
|
-
# @return [Enumerator]
|
41
|
-
# If no block is provided.
|
42
|
-
#
|
43
|
-
# @return [#each_pair | (#each_index & #each_with_index)]
|
44
|
-
# If a block is provided, the result of the `#each_pair` or
|
45
|
-
# `#each_with_index` call.
|
46
|
-
#
|
47
|
-
# @raise [NoMethodError]
|
48
|
-
# If `tree` does not respond to `#each_pair` or to `#each_index` and
|
49
|
-
# `#each_with_index`.
|
50
|
-
#
|
51
|
-
def self.each_branch tree, &block
|
52
|
-
if tree.respond_to? :each_pair
|
53
|
-
# Hash-like
|
54
|
-
tree.each_pair &block
|
55
|
-
|
56
|
-
elsif tree.respond_to? :each_index
|
57
|
-
# Array-like... we test for `each_index` because - unintuitively -
|
58
|
-
# `#each_with_index` is a method of {Enumerable}, meaning that {Set}
|
59
|
-
# responds to it, though sets are unordered and the values can't be
|
60
|
-
# accessed via those indexes. Hence we look for `#each_index`, which
|
61
|
-
# {Set} does not respond to.
|
62
|
-
|
63
|
-
if block.nil?
|
64
|
-
index_enumerator = tree.each_with_index
|
65
|
-
|
66
|
-
Enumerator.new( index_enumerator.size ) { |yielder|
|
67
|
-
index_enumerator.each { |value, index|
|
68
|
-
yielder.yield index, value
|
69
|
-
}
|
70
|
-
}
|
71
|
-
else
|
72
|
-
tree.each_with_index.map { |value, index|
|
73
|
-
block.call index, value
|
74
|
-
}
|
75
|
-
end
|
76
|
-
|
77
|
-
else
|
78
|
-
raise NoMethodError.new NRSER.squish <<-END
|
79
|
-
`tree` param must respond to `#each_pair` or `#each_index`,
|
80
|
-
found #{ tree.inspect }
|
81
|
-
END
|
82
|
-
|
83
|
-
end # if / else
|
84
|
-
end # .each_branch
|
85
|
-
|
86
|
-
end # module NRSER
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Definitions
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
module NRSER
|
5
|
+
|
6
|
+
# Enumerate over the immediate "branches" of a structure that can be used
|
7
|
+
# to compose our idea of a *tree*: nested hash-like and array-like structures
|
8
|
+
# like you would get from parsing a JSON document.
|
9
|
+
#
|
10
|
+
# Written and tested against Hash and Array instances, but should work with
|
11
|
+
# anything hash-like that responds to `#each_pair` appropriately or
|
12
|
+
# array-like that responds to `#each_index` and `#each_with_index`.
|
13
|
+
#
|
14
|
+
# @note Not sure what will happen if the tree has circular references!
|
15
|
+
#
|
16
|
+
# @param [#each_pair | (#each_index & #each_with_index)] tree
|
17
|
+
# Structure representing a tree via hash-like and array-like containers.
|
18
|
+
#
|
19
|
+
# @yieldparam [Object] key
|
20
|
+
# The first yielded param is the key or index for the value branch at the
|
21
|
+
# top level of `tree`.
|
22
|
+
#
|
23
|
+
# @yieldparam [Object] value
|
24
|
+
# The second yielded param is the branch at the key or index at the top
|
25
|
+
# level of `tree`.
|
26
|
+
#
|
27
|
+
# @yieldreturn
|
28
|
+
# Ignored.
|
29
|
+
#
|
30
|
+
# @return [Enumerator]
|
31
|
+
# If no block is provided.
|
32
|
+
#
|
33
|
+
# @return [#each_pair | (#each_index & #each_with_index)]
|
34
|
+
# If a block is provided, the result of the `#each_pair` or
|
35
|
+
# `#each_with_index` call.
|
36
|
+
#
|
37
|
+
# @raise [NoMethodError]
|
38
|
+
# If `tree` does not respond to `#each_pair` or to `#each_index` and
|
39
|
+
# `#each_with_index`.
|
40
|
+
#
|
41
|
+
def self.each_branch tree, &block
|
42
|
+
if tree.respond_to? :each_pair
|
43
|
+
# Hash-like
|
44
|
+
tree.each_pair &block
|
45
|
+
|
46
|
+
elsif tree.respond_to? :each_index
|
47
|
+
# Array-like... we test for `each_index` because - unintuitively -
|
48
|
+
# `#each_with_index` is a method of {Enumerable}, meaning that {Set}
|
49
|
+
# responds to it, though sets are unordered and the values can't be
|
50
|
+
# accessed via those indexes. Hence we look for `#each_index`, which
|
51
|
+
# {Set} does not respond to.
|
52
|
+
|
53
|
+
if block.nil?
|
54
|
+
index_enumerator = tree.each_with_index
|
55
|
+
|
56
|
+
Enumerator.new( index_enumerator.size ) { |yielder|
|
57
|
+
index_enumerator.each { |value, index|
|
58
|
+
yielder.yield [index, value]
|
59
|
+
}
|
60
|
+
}
|
61
|
+
else
|
62
|
+
tree.each_with_index.map { |value, index|
|
63
|
+
block.call [index, value]
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
else
|
68
|
+
raise NoMethodError.new NRSER.squish <<-END
|
69
|
+
`tree` param must respond to `#each_pair` or `#each_index`,
|
70
|
+
found #{ tree.inspect }
|
71
|
+
END
|
72
|
+
|
73
|
+
end # if / else
|
74
|
+
end # .each_branch
|
75
|
+
|
76
|
+
end # module NRSER
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Project / Package
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
require 'nrser/types/trees'
|
7
|
+
|
8
|
+
require_relative './each_branch'
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
module NRSER
|
15
|
+
|
16
|
+
# Map the immediate "branches" of a structure that can be used
|
17
|
+
# to compose our idea of a *tree*: nested hash-like and array-like structures
|
18
|
+
# like you would get from parsing a JSON document.
|
19
|
+
#
|
20
|
+
# The `block` **MUST** return a pair ({Array} of length 2), the first value
|
21
|
+
# of which is the key or index in the new {Hash} or {Array}.
|
22
|
+
#
|
23
|
+
# These pairs are then converted into a {Hash} or {Array} depending on it
|
24
|
+
# `tree` was {NRSER::Types.hash_like} or {NRSER::Types.array_like}, and
|
25
|
+
# that value is returned.
|
26
|
+
#
|
27
|
+
# Uses {NRSER.each_branch} internally.
|
28
|
+
#
|
29
|
+
# Written and tested against Hash and Array instances, but should work with
|
30
|
+
# anything:
|
31
|
+
#
|
32
|
+
# 1. *hash-like* that responds to `#each_pair` appropriately.
|
33
|
+
#
|
34
|
+
# 2. *array-like* that responds to `#each_index` and `#each_with_index`
|
35
|
+
# appropriately.
|
36
|
+
#
|
37
|
+
# @note Not sure what will happen if the tree has circular references!
|
38
|
+
#
|
39
|
+
# @todo
|
40
|
+
# Might be nice to have an option to preserve the tree class that creates
|
41
|
+
# a new instance of *whatever* it was and populates that, though I could
|
42
|
+
# see this relying on problematic assumptions and producing confusing
|
43
|
+
# results depending on the actual classes.
|
44
|
+
#
|
45
|
+
# Maybe this could be encoded in a mixin that we would detect or something.
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
#
|
49
|
+
#
|
50
|
+
#
|
51
|
+
# @param [#each_pair | (#each_index & #each_with_index)] tree
|
52
|
+
# Structure representing a tree via hash-like and array-like containers.
|
53
|
+
#
|
54
|
+
# @yieldparam [Object] key
|
55
|
+
# The first yielded param is the key or index for the value branch at the
|
56
|
+
# top level of `tree`.
|
57
|
+
#
|
58
|
+
# @yieldparam [Object] value
|
59
|
+
# The second yielded param is the branch at the key or index at the top
|
60
|
+
# level of `tree`.
|
61
|
+
#
|
62
|
+
# @yieldreturn [Array]
|
63
|
+
# Pair of key (/index) in new array or hash followed by value.
|
64
|
+
#
|
65
|
+
# @return [Array | Hash]
|
66
|
+
# If no block is provided.
|
67
|
+
#
|
68
|
+
# @raise [NoMethodError]
|
69
|
+
# If `tree` does not respond to `#each_pair` or to `#each_index` and
|
70
|
+
# `#each_with_index`.
|
71
|
+
#
|
72
|
+
def self.map_branches tree, &block
|
73
|
+
if block.nil?
|
74
|
+
raise ArgumentError, "Must provide block"
|
75
|
+
end
|
76
|
+
|
77
|
+
pairs = each_branch( tree ).map &block
|
78
|
+
|
79
|
+
Types.match tree,
|
80
|
+
Types.hash_like, ->( _ ) {
|
81
|
+
pairs.to_h
|
82
|
+
},
|
83
|
+
|
84
|
+
Types.array_like, ->( _ ) {
|
85
|
+
pairs.each_with_object( [] ) { |(index, value), array|
|
86
|
+
array[index] = value
|
87
|
+
}
|
88
|
+
}
|
89
|
+
end # .map_branches
|
90
|
+
|
91
|
+
end # module NRSER
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Project / Package
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
require_relative './map_branches'
|
7
|
+
|
8
|
+
|
9
|
+
# Definitions
|
10
|
+
# =======================================================================
|
11
|
+
|
12
|
+
module NRSER
|
13
|
+
# Recursively descend through a tree mapping *all* non-structural elements
|
14
|
+
# - anything not {NRSER::Types.hash_like} or {NRSER::Types.array_like}, both
|
15
|
+
# hash keys *and* values, as well as array entries - through `block` to
|
16
|
+
# produce a new structure.
|
17
|
+
#
|
18
|
+
# Useful when you want to translate pieces of a tree structure depending on
|
19
|
+
# their type or some other property that can be determined *from the element
|
20
|
+
# alone* - `block` receives only the value as an argument, no location
|
21
|
+
# information (because it's weirder to represent for keys and I didn't need
|
22
|
+
# it for the {NRSER.transformer} stuff this was written for).
|
23
|
+
#
|
24
|
+
# @note
|
25
|
+
# Array indexes **are not mapped** through `block` and can not be changed
|
26
|
+
# via this method. This makes it easier to do things like "convert all the
|
27
|
+
# integers to strings" when you mean the data entries, not the array
|
28
|
+
# indexes (which would fail since the new array wouldn't accept string
|
29
|
+
# indices).
|
30
|
+
#
|
31
|
+
# If you don't want to map hash keys use {NRSER.map_leaves}.
|
32
|
+
#
|
33
|
+
# See the specs for examples. Used in {NRSER.transformer}.
|
34
|
+
#
|
35
|
+
# @param tree (see NRSER.each_branch)
|
36
|
+
#
|
37
|
+
# @param [Boolean] prune:
|
38
|
+
# When `true`, prunes out values whose labels end with `?` and values are
|
39
|
+
# `nil`.
|
40
|
+
#
|
41
|
+
# @yieldparam [Object] element
|
42
|
+
# Anything reached from the root that is not structural (hash-like or
|
43
|
+
# array-like), including / inside hash keys (though array
|
44
|
+
# indexes are **not** passed).
|
45
|
+
#
|
46
|
+
def self.map_tree tree, prune: false, &block
|
47
|
+
# TODO type check tree?
|
48
|
+
|
49
|
+
mapped = tree.map { |element|
|
50
|
+
# Recur if `element` is a tree.
|
51
|
+
#
|
52
|
+
# Since `element` will be an {Array} of `key`, `value` when `tree` is a
|
53
|
+
# {Hash} (or similar), this will descend into hash keys that are also
|
54
|
+
# trees, as well as into hash values and array entries.
|
55
|
+
#
|
56
|
+
if Types.tree.test element
|
57
|
+
map_tree element, prune: prune, &block
|
58
|
+
else
|
59
|
+
# When we've run out of trees, finally pipe through the block:
|
60
|
+
block.call element
|
61
|
+
end
|
62
|
+
}
|
63
|
+
|
64
|
+
# If `tree` is hash-like, we want to convert the array of pair arrays
|
65
|
+
# back into a hash.
|
66
|
+
if Types.hash_like.test tree
|
67
|
+
if prune
|
68
|
+
pruned = {}
|
69
|
+
|
70
|
+
mapped.each { |key, value|
|
71
|
+
if Types.label.test( key ) &&
|
72
|
+
key.to_s.end_with?( '?' )
|
73
|
+
unless value.nil?
|
74
|
+
new_key = key.to_s[0..-2]
|
75
|
+
|
76
|
+
if key.is_a?( Symbol )
|
77
|
+
new_key = new_key.to_sym
|
78
|
+
end
|
79
|
+
|
80
|
+
pruned[new_key] = value
|
81
|
+
end
|
82
|
+
else
|
83
|
+
pruned[key] = value
|
84
|
+
end
|
85
|
+
}
|
86
|
+
|
87
|
+
pruned
|
88
|
+
else
|
89
|
+
mapped.to_h
|
90
|
+
end
|
91
|
+
else
|
92
|
+
# Getting here means it was array-like, so it's already fine
|
93
|
+
mapped
|
94
|
+
end
|
95
|
+
end # .map_branches
|
96
|
+
|
97
|
+
end # module NRSER
|
data/lib/nrser/tree/transform.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Project / Package
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
require_relative './map_tree'
|
7
|
+
|
1
8
|
# Definitions
|
2
9
|
# =======================================================================
|
3
10
|
|
@@ -12,19 +19,55 @@ module NRSER
|
|
12
19
|
# @todo Document return value.
|
13
20
|
#
|
14
21
|
def self.transform tree, source
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
else
|
23
|
-
value
|
24
|
-
end
|
25
|
-
end
|
26
|
-
}
|
27
|
-
}.to_h
|
22
|
+
map_tree( tree, prune: true ) { |value|
|
23
|
+
if value.is_a? Proc
|
24
|
+
value.call source
|
25
|
+
else
|
26
|
+
value
|
27
|
+
end
|
28
|
+
}
|
28
29
|
end # .transform
|
29
30
|
|
31
|
+
|
32
|
+
class SendSerializer
|
33
|
+
def initialize messages = []
|
34
|
+
@messages = messages
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing symbol, *args, &block
|
38
|
+
messages = [
|
39
|
+
*@messages,
|
40
|
+
::NRSER::Message.new( symbol, *args, &block )
|
41
|
+
]
|
42
|
+
|
43
|
+
self.class.new messages
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_proc publicly: true
|
47
|
+
::NRSER.chainer @messages, publicly: publicly
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
# @todo Document transformer method.
|
54
|
+
#
|
55
|
+
# @param [type] arg_name
|
56
|
+
# @todo Add name param description.
|
57
|
+
#
|
58
|
+
# @return [return_type]
|
59
|
+
# @todo Document return value.
|
60
|
+
#
|
61
|
+
def self.transformer &block
|
62
|
+
map_tree( block.call SendSerializer.new ) { |value|
|
63
|
+
if value.is_a? SendSerializer
|
64
|
+
value.to_proc
|
65
|
+
else
|
66
|
+
value
|
67
|
+
end
|
68
|
+
}
|
69
|
+
end # .transformer
|
70
|
+
|
71
|
+
|
72
|
+
|
30
73
|
end # module NRSER
|