nrser 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/nrser/char/alpha_numeric_sub.rb +1 -2
- data/lib/nrser/char.rb +0 -6
- data/lib/nrser/core_ext/array.rb +120 -0
- data/lib/nrser/core_ext/binding.rb +44 -0
- data/lib/nrser/{functions → core_ext}/enumerable/find_map.rb +18 -15
- data/lib/nrser/{ext → core_ext}/enumerable.rb +10 -24
- data/lib/nrser/core_ext/exception.rb +30 -0
- data/lib/nrser/core_ext/hash/extract_values_at.rb +49 -0
- data/lib/nrser/core_ext/hash/transform_values_with_keys.rb +24 -0
- data/lib/nrser/core_ext/hash.rb +50 -0
- data/lib/nrser/core_ext/module/method_objects.rb +96 -0
- data/lib/nrser/core_ext/module/names.rb +69 -0
- data/lib/nrser/core_ext/module/source_locations.rb +214 -0
- data/lib/nrser/core_ext/module.rb +2 -0
- data/lib/nrser/core_ext/object/lazy_var.rb +31 -0
- data/lib/nrser/core_ext/object.rb +46 -0
- data/lib/nrser/core_ext/open_struct.rb +6 -0
- data/lib/nrser/{ext → core_ext}/pathname.rb +8 -5
- data/lib/nrser/{ext → core_ext}/string.rb +6 -12
- data/lib/nrser/core_ext/symbol.rb +13 -0
- data/lib/nrser/core_ext/time.rb +46 -0
- data/lib/nrser/core_ext.rb +13 -0
- data/lib/nrser/errors/abstract_method_error.rb +150 -0
- data/lib/nrser/errors/argument_error.rb +42 -0
- data/lib/nrser/errors/nicer_error.rb +298 -72
- data/lib/nrser/errors/type_error.rb +46 -0
- data/lib/nrser/errors.rb +4 -53
- data/lib/nrser/ext/tree.rb +3 -0
- data/lib/nrser/functions/enumerable/associate.rb +6 -9
- data/lib/nrser/functions/enumerable/include_slice.rb +2 -3
- data/lib/nrser/functions/enumerable.rb +1 -3
- data/lib/nrser/functions/exception.rb +1 -1
- data/lib/nrser/functions/hash.rb +0 -6
- data/lib/nrser/functions/merge_by.rb +2 -2
- data/lib/nrser/functions/module/method_objects.rb +77 -0
- data/lib/nrser/functions/module.rb +1 -2
- data/lib/nrser/functions/open_struct.rb +25 -35
- data/lib/nrser/functions/proc.rb +1 -6
- data/lib/nrser/functions/string/looks_like.rb +32 -1
- data/lib/nrser/functions/string.rb +1 -40
- data/lib/nrser/functions/text/lines.rb +2 -1
- data/lib/nrser/functions.rb +0 -1
- data/lib/nrser/graph/tsorter.rb +41 -0
- data/lib/nrser/labs/core_ext/binding.rb +37 -0
- data/lib/nrser/labs/stash.rb +372 -0
- data/lib/nrser/{logging → log}/appender/sync.rb +3 -3
- data/lib/nrser/log/appender.rb +3 -0
- data/lib/nrser/{logging → log}/formatters/color.rb +47 -20
- data/lib/nrser/log/formatters/mixin.rb +270 -0
- data/lib/nrser/{logging → log}/formatters.rb +0 -0
- data/lib/nrser/log/logger.rb +229 -0
- data/lib/nrser/log/mixin.rb +56 -0
- data/lib/nrser/log.rb +723 -0
- data/lib/nrser/message.rb +24 -3
- data/lib/nrser/meta/source/location.rb +158 -0
- data/lib/nrser/meta.rb +1 -1
- data/lib/nrser/props/class_methods.rb +118 -0
- data/lib/nrser/props/immutable/hash.rb +111 -0
- data/lib/nrser/props/immutable/hash_variable.rb +82 -0
- data/lib/nrser/props/immutable/instance_variables.rb +48 -0
- data/lib/nrser/props/immutable/vector.rb +107 -0
- data/lib/nrser/props/instance_methods.rb +184 -0
- data/lib/nrser/props/metadata.rb +359 -0
- data/lib/nrser/props/mutable/instance_variables.rb +60 -0
- data/lib/nrser/props/mutable/stash.rb +199 -0
- data/lib/nrser/{meta/props → props}/prop.rb +217 -112
- data/lib/nrser/props/storage/instance_variable.rb +85 -0
- data/lib/nrser/props/storage/instance_variables.rb +67 -0
- data/lib/nrser/props/storage/key.rb +88 -0
- data/lib/nrser/props.rb +9 -0
- data/lib/nrser/refinements/sugar.rb +41 -0
- data/lib/nrser/refinements/types.rb +2 -2
- data/lib/nrser/refinements.rb +14 -16
- data/lib/nrser/rspex/example_group/describe_attribute.rb +24 -0
- data/lib/nrser/rspex/example_group/describe_called_with.rb +1 -6
- data/lib/nrser/rspex/example_group/{describe_use_case.rb → describe_case.rb} +6 -3
- data/lib/nrser/rspex/example_group/describe_class.rb +1 -0
- data/lib/nrser/rspex/example_group/describe_group.rb +29 -0
- data/lib/nrser/rspex/example_group/describe_instance_method.rb +2 -2
- data/lib/nrser/rspex/example_group/describe_message.rb +35 -0
- data/lib/nrser/rspex/example_group/describe_method.rb +23 -2
- data/lib/nrser/rspex/example_group/describe_module.rb +19 -0
- data/lib/nrser/rspex/example_group/describe_response_to.rb +32 -0
- data/lib/nrser/rspex/example_group/describe_section.rb +38 -0
- data/lib/nrser/rspex/example_group/describe_sent_to.rb +52 -0
- data/lib/nrser/rspex/example_group/describe_source_file.rb +49 -0
- data/lib/nrser/rspex/example_group/describe_spec_file.rb +41 -108
- data/lib/nrser/rspex/example_group/describe_when.rb +14 -7
- data/lib/nrser/rspex/example_group/describe_x.rb +39 -12
- data/lib/nrser/rspex/example_group/overrides.rb +66 -0
- data/lib/nrser/rspex/example_group.rb +20 -252
- data/lib/nrser/rspex/format.rb +83 -17
- data/lib/nrser/rspex.rb +4 -34
- data/lib/nrser/sugar/method_missing_forwarder.rb +50 -0
- data/lib/nrser/{env → sys/env}/path.rb +1 -2
- data/lib/nrser/{env.rb → sys/env.rb} +2 -1
- data/lib/nrser/sys.rb +5 -0
- data/lib/nrser/types/any.rb +36 -7
- data/lib/nrser/types/{array.rb → arrays.rb} +32 -81
- data/lib/nrser/types/attrs.rb +68 -15
- data/lib/nrser/types/booleans.rb +95 -34
- data/lib/nrser/types/bounded.rb +12 -10
- data/lib/nrser/types/combinators.rb +74 -37
- data/lib/nrser/types/errors/check_error.rb +86 -0
- data/lib/nrser/types/errors/from_string_error.rb +82 -0
- data/lib/nrser/types/factory.rb +91 -0
- data/lib/nrser/types/hashes.rb +171 -26
- data/lib/nrser/types/in.rb +25 -12
- data/lib/nrser/types/is.rb +50 -18
- data/lib/nrser/types/is_a.rb +52 -33
- data/lib/nrser/types/labels.rb +6 -33
- data/lib/nrser/types/maybe.rb +12 -4
- data/lib/nrser/types/nil.rb +24 -4
- data/lib/nrser/types/not.rb +6 -16
- data/lib/nrser/types/numbers.rb +94 -57
- data/lib/nrser/types/pairs.rb +57 -57
- data/lib/nrser/types/paths.rb +112 -133
- data/lib/nrser/types/responds.rb +64 -74
- data/lib/nrser/types/shape.rb +29 -24
- data/lib/nrser/types/strings.rb +25 -17
- data/lib/nrser/types/symbols.rb +19 -17
- data/lib/nrser/types/trees.rb +18 -70
- data/lib/nrser/types/tuples.rb +36 -40
- data/lib/nrser/types/type.rb +342 -91
- data/lib/nrser/types/when.rb +40 -18
- data/lib/nrser/types/where.rb +94 -9
- data/lib/nrser/types.rb +72 -63
- data/lib/nrser/version.rb +1 -1
- data/lib/nrser.rb +18 -18
- data/spec/lib/nrser/{functions/binding/template_spec.rb → core_ext/binding/erb_spec.rb} +5 -5
- data/spec/lib/nrser/{functions → core_ext}/enumerable/find_map_spec.rb +8 -6
- data/spec/lib/nrser/{refinements → core_ext}/hash_spec.rb +9 -22
- data/spec/lib/nrser/errors/abstract_method_error_spec.rb +12 -5
- data/spec/lib/nrser/functions/enumerable/{to_h_by_spec.rb → associate_spec.rb} +1 -1
- data/spec/lib/nrser/functions/merge_by_spec.rb +1 -1
- data/spec/lib/nrser/functions/tree/each_branch_spec.rb +3 -3
- data/spec/lib/nrser/functions/tree/transform_spec.rb +14 -15
- data/spec/lib/nrser/gem_ext/hamster/json_spec.rb +4 -0
- data/spec/lib/nrser/meta/source/location_spec.rb +86 -0
- data/spec/lib/nrser/props/immutable/hash_spec.rb +297 -0
- data/spec/lib/nrser/props/immutable/vector_spec.rb +296 -0
- data/spec/lib/nrser/{meta/props_spec.rb → props/original_props_spec.rb} +11 -16
- data/spec/lib/nrser/{meta/props → props}/to_and_from_data_spec.rb +10 -8
- data/spec/lib/nrser/refinements/array_spec.rb +2 -15
- data/spec/lib/nrser/refinements/erb_spec.rb +5 -7
- data/spec/lib/nrser/refinements/set_spec.rb +2 -15
- data/spec/lib/nrser/{env → sys/env}/path/insert_spec.rb +4 -2
- data/spec/lib/nrser/{env → sys/env}/path_spec.rb +4 -2
- data/spec/lib/nrser/types/array_spec.rb +8 -8
- data/spec/lib/nrser/types/paths_spec.rb +15 -18
- data/spec/spec_helper.rb +4 -0
- metadata +109 -69
- data/lib/nrser/ext/binding.rb +0 -36
- data/lib/nrser/ext/module.rb +0 -62
- data/lib/nrser/ext.rb +0 -8
- data/lib/nrser/functions/binding.rb +0 -76
- data/lib/nrser/functions/enumerable/map_keys.rb +0 -0
- data/lib/nrser/functions/enumerable/map_values.rb +0 -94
- data/lib/nrser/functions/hash/deep_merge.rb +0 -57
- data/lib/nrser/functions/hash/except_keys.rb +0 -44
- data/lib/nrser/functions/hash/slice_keys.rb +0 -43
- data/lib/nrser/functions/hash/stringify_keys.rb +0 -55
- data/lib/nrser/functions/hash/symbolize_keys.rb +0 -57
- data/lib/nrser/functions/hash/transform_keys.rb +0 -140
- data/lib/nrser/functions/module/methods.rb +0 -206
- data/lib/nrser/functions/module/source_locations.rb +0 -213
- data/lib/nrser/logging/appender.rb +0 -3
- data/lib/nrser/logging.rb +0 -353
- data/lib/nrser/meta/props/base.rb +0 -31
- data/lib/nrser/meta/props.rb +0 -357
- data/lib/nrser/refinements/array.rb +0 -133
- data/lib/nrser/refinements/binding.rb +0 -6
- data/lib/nrser/refinements/enumerator.rb +0 -5
- data/lib/nrser/refinements/exception.rb +0 -35
- data/lib/nrser/refinements/hash.rb +0 -150
- data/lib/nrser/refinements/module.rb +0 -5
- data/lib/nrser/refinements/object.rb +0 -42
- data/lib/nrser/refinements/open_struct.rb +0 -28
- data/lib/nrser/refinements/pathname.rb +0 -5
- data/lib/nrser/refinements/set.rb +0 -5
- data/lib/nrser/refinements/string.rb +0 -5
- data/lib/nrser/refinements/symbol.rb +0 -20
- data/lib/nrser/rspex/described.rb +0 -99
- data/spec/design/mapping_spec.rb +0 -42
- data/spec/lib/nrser/functions/hash_spec.rb +0 -41
- data/spec/lib/nrser/functions/string/truncate_spec.rb +0 -11
- data/spec/lib/nrser/refinements/truncate_spec.rb +0 -10
data/lib/nrser/message.rb
CHANGED
@@ -52,7 +52,7 @@ module NRSER
|
|
52
52
|
|
53
53
|
# Name of method the message is for.
|
54
54
|
#
|
55
|
-
# @return [Symbol
|
55
|
+
# @return [Symbol]
|
56
56
|
#
|
57
57
|
attr_reader :symbol
|
58
58
|
|
@@ -83,12 +83,33 @@ module NRSER
|
|
83
83
|
# Optional block that should be sent.
|
84
84
|
#
|
85
85
|
def initialize symbol, *args, &block
|
86
|
-
@symbol = symbol
|
86
|
+
@symbol = symbol.to_sym
|
87
87
|
@args = args
|
88
88
|
@block = block
|
89
89
|
end
|
90
90
|
|
91
91
|
|
92
|
+
def options
|
93
|
+
if args.last.is_a? Hash
|
94
|
+
args.last
|
95
|
+
else
|
96
|
+
{}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def symbolize_options
|
102
|
+
if args.last.is_a? Hash
|
103
|
+
self.class.new \
|
104
|
+
symbol,
|
105
|
+
*args[0..-2],
|
106
|
+
args.last.sym_keys
|
107
|
+
else
|
108
|
+
self
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
92
113
|
# Creates a {Proc} that accepts a single `receiver` argument and calls
|
93
114
|
# {#sent_to} on it, allowing messages to be used via the `&` operator
|
94
115
|
# in `map`, etc.
|
@@ -114,7 +135,7 @@ module NRSER
|
|
114
135
|
end
|
115
136
|
|
116
137
|
alias_method :to_sender, :to_proc
|
117
|
-
|
138
|
+
|
118
139
|
|
119
140
|
# Send this instance to a receiver object.
|
120
141
|
#
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
|
16
|
+
require 'nrser/props'
|
17
|
+
require 'nrser/props/immutable/vector'
|
18
|
+
|
19
|
+
|
20
|
+
# Refinements
|
21
|
+
# =======================================================================
|
22
|
+
|
23
|
+
using NRSER::Types
|
24
|
+
|
25
|
+
|
26
|
+
# Declarations
|
27
|
+
# =======================================================================
|
28
|
+
|
29
|
+
module NRSER::Meta::Source; end
|
30
|
+
|
31
|
+
|
32
|
+
# Definitions
|
33
|
+
# =======================================================================
|
34
|
+
|
35
|
+
# @todo document NRSER::Meta::Source::Location class.
|
36
|
+
#
|
37
|
+
class NRSER::Meta::Source::Location < Hamster::Vector
|
38
|
+
|
39
|
+
# Mixins
|
40
|
+
# ============================================================================
|
41
|
+
|
42
|
+
include NRSER::Props::Immutable::Vector
|
43
|
+
|
44
|
+
|
45
|
+
# Class Methods
|
46
|
+
# ============================================================================
|
47
|
+
|
48
|
+
# Given an {Enumerable} of {Method} objects, return a {Hash} mapping their
|
49
|
+
# {Method#name} to the method's {NRSER::Meta::Source::Location}.
|
50
|
+
#
|
51
|
+
# @note
|
52
|
+
# We map the names instead of the {Method} objects themselves because
|
53
|
+
# aliases produce two different {Method} objects that `#==` and `#hash`
|
54
|
+
# the same, preventing them both from being {Hash} keys.
|
55
|
+
#
|
56
|
+
# @param [Enumerable<Method>] methods
|
57
|
+
# Methods you want the source locations for.
|
58
|
+
#
|
59
|
+
# @param [Boolean] only_valid:
|
60
|
+
# When `true` filter the results to only those that are {#valid?}.
|
61
|
+
#
|
62
|
+
# @return [Hash<Symbol, NRSER::Meta::Source::Location>]
|
63
|
+
# Map of method name to their source locations.
|
64
|
+
#
|
65
|
+
def self.for_methods methods, only_valid: false
|
66
|
+
all = methods.map { |method|
|
67
|
+
[ method.name, NRSER::Meta::Source::Location.new( method ) ]
|
68
|
+
}.to_h
|
69
|
+
|
70
|
+
if only_valid
|
71
|
+
all.select { |method, location| location.valid? }
|
72
|
+
else
|
73
|
+
all
|
74
|
+
end
|
75
|
+
end # .for_methods
|
76
|
+
|
77
|
+
|
78
|
+
# Props
|
79
|
+
# ======================================================================
|
80
|
+
|
81
|
+
prop :file, type: t.abs_path?, default: nil, index: 0
|
82
|
+
prop :line, type: t.pos_int?, default: nil, index: 1
|
83
|
+
|
84
|
+
|
85
|
+
# Constructor
|
86
|
+
# ============================================================================
|
87
|
+
|
88
|
+
# Override to allow argument to be `nil` for when {Method#source_location}
|
89
|
+
# weirdly returns `nil`.
|
90
|
+
#
|
91
|
+
# @param [(#[] & (#each_pair | #each_index)) | nil ] source
|
92
|
+
# Source to construct from:
|
93
|
+
#
|
94
|
+
# 1. `#[] & (#each_pair | #each_index)`
|
95
|
+
# 1. Hash-like that responds to `#each_pair` and contains prop
|
96
|
+
# value sources keyed by their names.
|
97
|
+
#
|
98
|
+
# Supports standard propertied class construction.
|
99
|
+
#
|
100
|
+
# **Examples:**
|
101
|
+
#
|
102
|
+
# {file: '/some/abs/path.rb', line: 88}
|
103
|
+
# {file: '/some/abs/path.rb', line: nil}
|
104
|
+
# {file: nil, line: 88}
|
105
|
+
# {file: nil, line: nil}
|
106
|
+
# {}
|
107
|
+
#
|
108
|
+
# 2. Array-like that responds to `#each_index` and contains prop
|
109
|
+
# values sources indexed by their non-negative integer indexes.
|
110
|
+
#
|
111
|
+
# Supports the output of {Method#source_location}.
|
112
|
+
#
|
113
|
+
# **Examples:**
|
114
|
+
#
|
115
|
+
# ['/some/abs/path.rb', 88]
|
116
|
+
# ['/some/abs/path.rb', nil]
|
117
|
+
# [nil, 88]
|
118
|
+
# [nil, nil]
|
119
|
+
# []
|
120
|
+
#
|
121
|
+
# 2. `nil` - Swapped for `{]` to support times I'm pretty sure I've seen
|
122
|
+
# {Method#source_location} return strait-up `nil`.
|
123
|
+
#
|
124
|
+
#
|
125
|
+
def initialize source
|
126
|
+
source = source.source_location if source.respond_to? :source_location
|
127
|
+
source = {} if source.nil?
|
128
|
+
super source
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
# Instance Methods
|
133
|
+
# ======================================================================
|
134
|
+
|
135
|
+
# Do we have a file and a line?
|
136
|
+
#
|
137
|
+
# Sometimes `#source_location` gives back `nil` values or just `nil`
|
138
|
+
# (in which case we set both {#file} and {#line} to `nil`). I think this
|
139
|
+
# has to do with C extensions and other weirdness.
|
140
|
+
#
|
141
|
+
# Anyways, this helps you handle it.
|
142
|
+
#
|
143
|
+
# @return [Boolean]
|
144
|
+
#
|
145
|
+
def valid?
|
146
|
+
!( file.nil? && line.nil? )
|
147
|
+
end # #valid?
|
148
|
+
|
149
|
+
|
150
|
+
# @return [String]
|
151
|
+
# a short string describing the instance.
|
152
|
+
#
|
153
|
+
def to_s
|
154
|
+
"#{ file || '???' }:#{ line || '???' }"
|
155
|
+
end # #to_s
|
156
|
+
|
157
|
+
|
158
|
+
end # class NRSER::Meta::Source::Location
|
data/lib/nrser/meta.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
require_relative './metadata'
|
16
|
+
|
17
|
+
# Refinements
|
18
|
+
# =======================================================================
|
19
|
+
|
20
|
+
|
21
|
+
# Declarations
|
22
|
+
# =======================================================================
|
23
|
+
|
24
|
+
module NRSER::Props; end
|
25
|
+
|
26
|
+
|
27
|
+
# Definitions
|
28
|
+
# =======================================================================
|
29
|
+
|
30
|
+
|
31
|
+
# Class method "macros" that are extended in to data classes, providing the
|
32
|
+
# declaration interface.
|
33
|
+
#
|
34
|
+
module NRSER::Props::ClassMethods
|
35
|
+
|
36
|
+
include NRSER::Log::Mixin
|
37
|
+
|
38
|
+
# Get the metadata object for this class, creating it if it doesn't exist.
|
39
|
+
#
|
40
|
+
# @return [NRSER::Props::Metadata]
|
41
|
+
#
|
42
|
+
def metadata
|
43
|
+
# TODO Move into {NRSER::Props::Metadata}?
|
44
|
+
#
|
45
|
+
unless NRSER::Props::Metadata.has_metadata? self
|
46
|
+
instance_variable_set \
|
47
|
+
NRSER::Props::Metadata::VARIABLE_NAME,
|
48
|
+
NRSER::Props::Metadata.new( self )
|
49
|
+
end
|
50
|
+
|
51
|
+
NRSER::Props::Metadata.metadata_for self
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def props *args, &block
|
56
|
+
metadata.props *args, &block
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def prop *args, &block
|
61
|
+
metadata.prop *args, &block
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def invariants *args, &block
|
66
|
+
metadata.invariants *args, &block
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def invariant *args, &block
|
71
|
+
metadata.invariant *args, &block
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Instantiate from a data hash.
|
76
|
+
#
|
77
|
+
# @todo
|
78
|
+
# This needs to be extended to handle prop'd classes nested in
|
79
|
+
# arrays and hashes... but for the moment, it is what it is.
|
80
|
+
#
|
81
|
+
# This *may* have been fixed...?
|
82
|
+
#
|
83
|
+
# @param [#each_pair] data
|
84
|
+
#
|
85
|
+
# @return [self]
|
86
|
+
#
|
87
|
+
# @raise [NRSER::ArgumentError]
|
88
|
+
# If `data` does not respond to `#each_pair`.
|
89
|
+
#
|
90
|
+
def from_data data
|
91
|
+
values = {}
|
92
|
+
props = self.props
|
93
|
+
|
94
|
+
unless data.respond_to? :each_pair
|
95
|
+
raise NRSER::ArgumentError.new \
|
96
|
+
"`data` argument must respond to `#each_pair`",
|
97
|
+
data: data,
|
98
|
+
class: self
|
99
|
+
end
|
100
|
+
|
101
|
+
data.each_pair do |data_key, data_value|
|
102
|
+
prop_key = case data_key
|
103
|
+
when Symbol
|
104
|
+
data_key
|
105
|
+
when String
|
106
|
+
data_key.to_sym
|
107
|
+
end
|
108
|
+
|
109
|
+
if prop_key &&
|
110
|
+
(prop = props[prop_key])
|
111
|
+
values[prop_key] = prop.value_from_data data_value
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
self.new values
|
116
|
+
end # #from_data
|
117
|
+
|
118
|
+
end # module NRSER::Props::ClassMethods
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
require 'hamster'
|
10
|
+
|
11
|
+
# Project / Package
|
12
|
+
# -----------------------------------------------------------------------
|
13
|
+
require_relative '../storage/key'
|
14
|
+
|
15
|
+
|
16
|
+
# Declarations
|
17
|
+
# =======================================================================
|
18
|
+
|
19
|
+
module NRSER::Props::Immutable; end
|
20
|
+
|
21
|
+
|
22
|
+
# Definitions
|
23
|
+
# =======================================================================
|
24
|
+
|
25
|
+
# Mixin for classes that extend {Hamster::Hash} and will use itself as the
|
26
|
+
# property value storage.
|
27
|
+
#
|
28
|
+
module NRSER::Props::Immutable::Hash
|
29
|
+
|
30
|
+
# Constants
|
31
|
+
# ==========================================================================
|
32
|
+
|
33
|
+
STORAGE = NRSER::Props::Storage::Key.new immutable: true, key_type: :name
|
34
|
+
|
35
|
+
|
36
|
+
# Module Methods
|
37
|
+
# ======================================================================
|
38
|
+
|
39
|
+
def self.included base
|
40
|
+
unless base < Hamster::Hash
|
41
|
+
raise binding.erb <<~END
|
42
|
+
This class is only for including in {Hamster::Hash} subclasses!
|
43
|
+
END
|
44
|
+
end
|
45
|
+
|
46
|
+
base.include NRSER::Props
|
47
|
+
base.metadata.storage STORAGE
|
48
|
+
base.metadata.freeze
|
49
|
+
|
50
|
+
base.extend ClassMethods
|
51
|
+
base.include InstanceMethods
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# Mixin Methods
|
56
|
+
# ======================================================================
|
57
|
+
|
58
|
+
# Methods mixed in at the class-level.
|
59
|
+
#
|
60
|
+
module ClassMethods
|
61
|
+
# {Hamster::Hash} uses `.alloc` to quickly create derived instances
|
62
|
+
# when it knows the instance variables. We need to hook into that to
|
63
|
+
# check the prop types.
|
64
|
+
#
|
65
|
+
# @param (see Hamster::Hash.alloc)
|
66
|
+
#
|
67
|
+
# @return [Hamster::Hash]
|
68
|
+
# The new instance, which will be of the propertied subclass of
|
69
|
+
# {Hamster::Hash}.
|
70
|
+
#
|
71
|
+
# @raise [TypeError]
|
72
|
+
# If the prop values of the new vector don't satisfy the prop types.
|
73
|
+
#
|
74
|
+
def alloc *args
|
75
|
+
super( *args ).tap do |new_instance|
|
76
|
+
self.props( only_primary: true ).values.each do |prop|
|
77
|
+
prop.check! new_instance[prop.name]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end # module ClassMethods
|
82
|
+
|
83
|
+
module InstanceMethods
|
84
|
+
# Constructor
|
85
|
+
# ----------------------------------------------------------------------------
|
86
|
+
|
87
|
+
# Since including classes are using themselves as storage, we need to tap
|
88
|
+
# into the `#initialize` chain in order to load property values from sources
|
89
|
+
# and pass an {Array} up to the super-method to instantiate the
|
90
|
+
# {Hamster::Hash}.
|
91
|
+
#
|
92
|
+
def initialize values = {}
|
93
|
+
# Handles things like `[[:x, 1], [:y, 2]]`
|
94
|
+
values = values.to_h unless values.respond_to?( :each_pair )
|
95
|
+
|
96
|
+
super_values = {}
|
97
|
+
|
98
|
+
self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
|
99
|
+
super_values[prop.name] = value
|
100
|
+
}
|
101
|
+
|
102
|
+
super super_values
|
103
|
+
|
104
|
+
# Check additional type invariants
|
105
|
+
self.class.invariants.each do |type|
|
106
|
+
type.check self
|
107
|
+
end
|
108
|
+
end # #initialize
|
109
|
+
end
|
110
|
+
|
111
|
+
end # module NRSER::Props::Immutable::Hash
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Stdlib
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Project / Package
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
require_relative '../storage/key'
|
13
|
+
require_relative '../storage/instance_variable'
|
14
|
+
|
15
|
+
|
16
|
+
# Declarations
|
17
|
+
# =======================================================================
|
18
|
+
|
19
|
+
module NRSER; end
|
20
|
+
module NRSER::Props; end
|
21
|
+
|
22
|
+
|
23
|
+
# Definitions
|
24
|
+
# =======================================================================
|
25
|
+
|
26
|
+
# Mix-in to store property values in an immutable {Hamster::Hash} instance
|
27
|
+
# in an instance variable.
|
28
|
+
#
|
29
|
+
# This is basically an improvement of how the original props implementation
|
30
|
+
# worked.
|
31
|
+
#
|
32
|
+
module NRSER::Props::Immutable::HashVariable
|
33
|
+
|
34
|
+
KEY_STORAGE = NRSER::Props::Storage::Key.new immutable: true, key_type: :name
|
35
|
+
|
36
|
+
INSTANCE_VARIABLE_STORAGE = \
|
37
|
+
NRSER::Props::Storage::InstanceVariable.new sub_storage: KEY_STORAGE
|
38
|
+
|
39
|
+
|
40
|
+
# Class Methods
|
41
|
+
# ======================================================================
|
42
|
+
|
43
|
+
def self.included base
|
44
|
+
base.include NRSER::Props
|
45
|
+
base.metadata.storage INSTANCE_VARIABLE_STORAGE
|
46
|
+
base.metadata.freeze
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Constructor
|
51
|
+
# ======================================================================
|
52
|
+
|
53
|
+
# Instantiate a new `NRSER::Props::Immutable::Vector`.
|
54
|
+
def initialize_props values = {}
|
55
|
+
prop_values = {}
|
56
|
+
|
57
|
+
self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
|
58
|
+
prop_values[prop.name] = value
|
59
|
+
}
|
60
|
+
|
61
|
+
instance_variable_set self.class.metadata.storage.var_name,
|
62
|
+
Hamster::Hash.new( values )
|
63
|
+
|
64
|
+
# Check additional type invariants
|
65
|
+
self.class.invariants.each do |type|
|
66
|
+
type.check self
|
67
|
+
end
|
68
|
+
end # #initialize
|
69
|
+
|
70
|
+
end # module NRSER::Props::Immutable::HashVariable
|
71
|
+
|
72
|
+
|
73
|
+
# @todo document NRSER::Props::Immutable::HashVariable::Base module.
|
74
|
+
class NRSER::Props::Immutable::HashVariable::Base
|
75
|
+
|
76
|
+
include NRSER::Props::Immutable::HashVariable
|
77
|
+
|
78
|
+
def initialize values = {}
|
79
|
+
initialize_props values
|
80
|
+
end
|
81
|
+
|
82
|
+
end # class NRSER::Props::Immutable::HashVariable::Base
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Project / Package
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
require_relative '../../props'
|
7
|
+
require_relative '../storage/key'
|
8
|
+
require_relative '../storage/instance_variables'
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
# Mix-in to store property values in instance variables of the same name.
|
15
|
+
#
|
16
|
+
module NRSER::Props::Immutable::InstanceVariables
|
17
|
+
|
18
|
+
STORAGE = NRSER::Props::Storage::InstanceVariables.new immutable: true
|
19
|
+
|
20
|
+
|
21
|
+
# Class Methods
|
22
|
+
# ======================================================================
|
23
|
+
|
24
|
+
def self.included base
|
25
|
+
base.include NRSER::Props
|
26
|
+
base.metadata.storage STORAGE
|
27
|
+
base.metadata.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# Instance Methods
|
32
|
+
# ======================================================================
|
33
|
+
|
34
|
+
# Since the {NRSER::Props::Immutable::InstanceVariables} mix-in does *not*
|
35
|
+
# need to tap into the initialize chain,
|
36
|
+
#
|
37
|
+
def initialize_props values = {}
|
38
|
+
self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
|
39
|
+
instance_variable_set "@#{ prop.name }", value
|
40
|
+
}
|
41
|
+
|
42
|
+
# Check additional type invariants
|
43
|
+
self.class.invariants.each do |type|
|
44
|
+
type.check self
|
45
|
+
end
|
46
|
+
end # #initialize_props
|
47
|
+
|
48
|
+
end # module NRSER::Props::Immutable
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
require 'hamster'
|
10
|
+
|
11
|
+
# Project / Package
|
12
|
+
# -----------------------------------------------------------------------
|
13
|
+
require_relative '../storage/key'
|
14
|
+
|
15
|
+
|
16
|
+
# Declarations
|
17
|
+
# =======================================================================
|
18
|
+
|
19
|
+
module NRSER::Props::Immutable; end
|
20
|
+
|
21
|
+
|
22
|
+
# Definitions
|
23
|
+
# =======================================================================
|
24
|
+
|
25
|
+
# Mixin for classes that extend {Hamster::Vector} and will use itself as the
|
26
|
+
# property value storage, requiring that property keys be non-negative
|
27
|
+
# integers.
|
28
|
+
#
|
29
|
+
module NRSER::Props::Immutable::Vector
|
30
|
+
|
31
|
+
# Constants
|
32
|
+
# ==========================================================================
|
33
|
+
|
34
|
+
STORAGE = NRSER::Props::Storage::Key.new immutable: true, key_type: :index
|
35
|
+
|
36
|
+
|
37
|
+
# Module Methods
|
38
|
+
# ======================================================================
|
39
|
+
|
40
|
+
def self.included base
|
41
|
+
unless base < Hamster::Vector
|
42
|
+
raise binding.erb <<~END
|
43
|
+
This class is only for including in {Hamster::Vector} subclasses!
|
44
|
+
END
|
45
|
+
end
|
46
|
+
|
47
|
+
base.include NRSER::Props
|
48
|
+
base.metadata.storage STORAGE
|
49
|
+
base.metadata.freeze
|
50
|
+
|
51
|
+
base.extend ClassMethods
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# Mixin Methods
|
56
|
+
# ======================================================================
|
57
|
+
|
58
|
+
# Methods mixed in at the class-level.
|
59
|
+
#
|
60
|
+
module ClassMethods
|
61
|
+
# {Hamster::Vector} uses `.alloc` to quickly create derived instances
|
62
|
+
# when it knows the instance variables. We need to hook into that to
|
63
|
+
# check the prop types.
|
64
|
+
#
|
65
|
+
# @param (see Hamster::Vector.alloc)
|
66
|
+
#
|
67
|
+
# @return [Hamster::Vector]
|
68
|
+
# The new instance, which will be of the propertied subclass of
|
69
|
+
# {Hamster::Vector}.
|
70
|
+
#
|
71
|
+
# @raise [TypeError]
|
72
|
+
# If the prop values of the new vector don't satisfy the prop types.
|
73
|
+
#
|
74
|
+
def alloc *args
|
75
|
+
super( *args ).tap do |new_instance|
|
76
|
+
self.props( only_primary: true ).each_value do |prop|
|
77
|
+
prop.check! new_instance[prop.index]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end # module ClassMethods
|
82
|
+
|
83
|
+
|
84
|
+
# Constructor
|
85
|
+
# ----------------------------------------------------------------------------
|
86
|
+
|
87
|
+
# Since including classes are using themselves as storage, we need to tap
|
88
|
+
# into the `#initialize` chain in order to load property values from sources
|
89
|
+
# and pass an {Array} up to the super-method to instantiate the
|
90
|
+
# {Hamster::Vector}.
|
91
|
+
#
|
92
|
+
def initialize values = {}
|
93
|
+
super_values = []
|
94
|
+
|
95
|
+
self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
|
96
|
+
super_values[prop.index] = value
|
97
|
+
}
|
98
|
+
|
99
|
+
super super_values
|
100
|
+
|
101
|
+
# Check additional type invariants
|
102
|
+
self.class.invariants.each do |type|
|
103
|
+
type.check self
|
104
|
+
end
|
105
|
+
end # #initialize
|
106
|
+
|
107
|
+
end # module NRSER::Props::Immutable::Vector
|