nrser 0.1.3 → 0.1.4

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.
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Requirements
4
+ # =======================================================================
5
+
6
+ # Stdlib
7
+ # -----------------------------------------------------------------------
8
+
9
+ # Deps
10
+ # -----------------------------------------------------------------------
11
+
12
+ # Project / Package
13
+ # -----------------------------------------------------------------------
14
+
15
+
16
+ # Refinements
17
+ # =======================================================================
18
+
19
+
20
+ # Declarations
21
+ # =======================================================================
22
+
23
+ module NRSER::Labs; end
24
+
25
+
26
+
27
+ # Definitions
28
+ # =======================================================================
29
+
30
+ # A very basic index data structure that
31
+ class NRSER::Labs::Index
32
+
33
+ # Attributes
34
+ # ======================================================================
35
+
36
+
37
+ # Constructor
38
+ # ======================================================================
39
+
40
+ # Instantiate a new `NRSER::Index`.
41
+ def initialize entries = nil, sort: false, &indexer
42
+ @indexer = indexer
43
+ @hash = Hash.new { |hash, key| hash[key] = Set.new }
44
+
45
+ add( *entries ) if entries
46
+ end # #initialize
47
+
48
+
49
+ # Instance Methods
50
+ # ======================================================================
51
+
52
+ def key_for entry
53
+ @indexer.call entry
54
+ end
55
+
56
+
57
+ def keys
58
+ Set.new @hash.keys
59
+ end
60
+
61
+
62
+ def values
63
+ @hash.values.reduce :+
64
+ end
65
+
66
+
67
+ def [] key
68
+ @hash[key]
69
+ end
70
+
71
+
72
+ def add *entries
73
+ entries.each do |entry|
74
+ @hash[key_for( entry )].add entry
75
+ end
76
+
77
+ self
78
+ end
79
+
80
+
81
+ def remove *entries
82
+ entries.each do |entry|
83
+ @hash[key_for( entry )].remove entry
84
+ end
85
+
86
+ self
87
+ end
88
+
89
+ end # class NRSER::Index
@@ -1,4 +1,4 @@
1
- module NRSER
1
+ module NRSER::Labs
2
2
  module UnicodeMath
3
3
  SET_STARTS = {
4
4
  bold: {
@@ -45,4 +45,4 @@ module NRSER
45
45
  CharacterTranslator.new name, starts[:upper], starts[:lower]
46
46
  end
47
47
  end
48
- end
48
+ end
@@ -1,9 +1,7 @@
1
-
2
-
3
1
  # Definitions
4
2
  # =======================================================================
5
3
 
6
- module NRSER
4
+ module NRSER::Labs
7
5
 
8
6
  # A class to hold info about how to find a record (besides by primary key).
9
7
  #
@@ -16,7 +14,7 @@ module NRSER
16
14
  # {NRSER::Types::Where}...
17
15
  #
18
16
  # Maybe this functionality has something to do with the types system?
19
- # It seems like the placeholder stuff would be hard to integrate with
17
+ # It seems like the placeholder stuff would be hard to integrate with
20
18
  # that, but having a whole other very similar system sucks too.
21
19
  #
22
20
  class Where
@@ -188,16 +188,19 @@ module NRSER::Meta::Props
188
188
  prop = Prop.new self, name, **opts
189
189
  ref[name] = prop
190
190
 
191
- unless prop.source?
191
+ if prop.create_reader?
192
192
  class_eval do
193
- define_method(name) do
193
+ define_method prop.name do
194
194
  prop.get self
195
195
  end
196
-
197
- # protected
198
- # define_method("#{ name }=") do |value|
199
- # prop.set self, value
200
- # end
196
+ end
197
+ end
198
+
199
+ if prop.create_writer?
200
+ class_eval do
201
+ define_method "#{ prop.name }=" do |value|
202
+ prop.set self, value
203
+ end
201
204
  end
202
205
  end
203
206
 
@@ -255,6 +258,9 @@ module NRSER::Meta::Props
255
258
  self.class.props(only_primary: true).each { |name, prop|
256
259
  prop.set_from_values_hash self, values
257
260
  }
261
+
262
+ # TODO Now trigger all eager defaults (check prop getting trigger
263
+ # correctly)
258
264
  end # #initialize_props
259
265
 
260
266
 
@@ -52,7 +52,18 @@ class NRSER::Meta::Props::Prop
52
52
  # Props that have a source are considered *derived*, those that don't are
53
53
  # called *primary*.
54
54
  #
55
- # @return [Symbol | String]
55
+ # @return [nil]
56
+ # When this prop is a *primary* property and receives it's value at
57
+ # initialization or from a {#default}.
58
+ #
59
+ # @return [Symbol]
60
+ # This prop is *derived* by returning an instance variable if the symbol
61
+ # starts with `@` or otherwise by sending the symbol to the prop'd instance
62
+ # (calling that method with no arguments).
63
+ #
64
+ # @return [Proc]
65
+ # This prop is *derived* by evaluating this {Proc} in the prop'd
66
+ # instance.
56
67
  #
57
68
  attr_reader :source
58
69
 
@@ -67,18 +78,34 @@ class NRSER::Meta::Props::Prop
67
78
  # `.prop` "macro" defined at {NRSER::Meta::Props::ClassMethods#prop}
68
79
  # that is extended in to classes including {NRSER::Meta::Props}.
69
80
  #
81
+ # @param [nil | Proc | Object] default:
82
+ # A default value or a {Proc} used to get default values for *primary*
83
+ # props. *Dervied* props (those that have a {#source}) may not
84
+ #
85
+ # At least one of `default:` and `source:` must be `nil`.
86
+ #
87
+ # @param [nil | Symbol | String | Proc] source:
88
+ # Source that provides the prop's value. See details for how each type is
89
+ # handled in {#source}. Strings are converted to symbols.
90
+ #
91
+ # At least one of `default:` and `source:` must be `nil`.
92
+ #
93
+ # @raise [ArgumentError]
94
+ # If `default:` is not `nil` *and* `source:` is not `nil`.
95
+ #
96
+ # @raise
97
+ #
70
98
  def initialize defined_in,
71
99
  name,
72
100
  type: t.any,
73
101
  default: nil,
74
- default_from: nil,
75
102
  source: nil,
76
103
  to_data: nil,
77
104
  from_data: nil
78
105
 
79
106
  # Set these up first so {#to_s} works in case we need to raise errors.
80
107
  @defined_in = defined_in
81
- @name = name
108
+ @name = t.sym.check name
82
109
  @type = t.make type
83
110
 
84
111
  @to_data = to_data
@@ -86,90 +113,121 @@ class NRSER::Meta::Props::Prop
86
113
 
87
114
  # Source
88
115
 
89
- @source = source # TODO fix this: t.maybe( t.label ).check source
116
+ # normalize source to {nil}, {Symbol} or {Proc}
117
+ @source = t.match source,
118
+ nil, nil,
119
+ String, ->( string ) { string.to_sym },
120
+ Symbol, source,
121
+ Proc, ->(){ source }
90
122
 
91
- # Detect if the source
92
- if source.nil?
93
- @instance_variable_source = false
94
- else
95
- # TODO Check that default and default_from are `nil`, make no sense here
96
-
97
- source_str = source.to_s
98
- @instance_variable_source = source_str[0] == '@'
99
- end
123
+ # Detect if the source points to an instance variable (`:'@name'`-formatted
124
+ # symbol).
125
+ @instance_variable_source = \
126
+ @source.is_a?( Symbol ) && @source.to_s[0] == '@'
100
127
 
101
- # Defaults
128
+ init_default! default
102
129
 
103
- # Can't provide both default and default_from
104
- unless default.nil? || default_from.nil?
105
- raise NRSER::ConflictError.new binding.erb <<-ERB
106
- Both `default:` and `default_from:` keyword args provided when
107
- constructing <%= self %>. At least one must be `nil`.
108
-
109
- default:
110
- <%= default.pretty_inspect %>
111
-
112
- default_from:
113
- <%= default_from.pretty_inspect %>
114
-
115
- ERB
116
- end
130
+ end # #initialize
131
+
132
+
133
+ protected
134
+ # ========================================================================
117
135
 
118
- if default_from.nil?
119
- # We are going to use `default`
120
-
121
- # Validate `default` value
136
+
137
+ def init_default! default
122
138
  if default.nil?
123
- # If it's `nil` we still want to see if it's a valid value for the type
124
- # so we can report if this prop has a default value or not.
125
- #
126
- # However, we only need to do that if there is no `source`
127
- #
128
- @has_default = if source.nil?
129
- @type.test default
130
- else
131
- # NOTE This is up for debate... does a derived property have a
132
- # default? What does that even mean?
133
- true # false ?
134
- end
135
-
136
- else
137
- # Check that the default value is valid for the type, raising TypeError
138
- # if it isn't.
139
- @type.check( default ) { |type:, value:|
140
- binding.erb <<-ERB
141
- Default value is not valid for <%= self %>:
142
-
143
- <%= value.pretty_inspect %>
144
-
145
- ERB
146
- }
147
-
148
- # If we passed the check we know the value is valid
149
- @has_default = true
150
-
151
- # Set the default value to `default`, freezing it since it will be
152
- # set on instances without any attempt at duplication, which seems like
153
- # it *might be ok* since a lot of prop'd classes are being used
154
- # immutably.
155
- @default_value = default.freeze
139
+ # If it's `nil`, we will use it as the default value *if* this
140
+ # is a primary prop *and* the type is satisfied by `nil`
141
+ @has_default = source? && @type.test( default )
142
+ return
156
143
  end
157
144
 
158
- else
159
- # `default_from` is not `nil`, so we're going to use that.
145
+ # Now the we know that the default isn't `nil`, we want to check that
146
+ # the prop doesn't have a source, because defaults don't make any sense
147
+ # for sourced props
148
+ if source?
149
+ raise ArgumentError.new binding.erb <<-END
150
+ Can not construct {<%= self.class.name %>} with `default` and `source`
151
+
152
+ Props with {#source} always get their value from that source, so
153
+ defaults don't make any sense.
154
+
155
+ Attempted to construct prop <%= name.inspect %> for class
156
+ {<%= defined_in.name %>} with:
157
+
158
+ default:
159
+
160
+ <%= default.pretty_inspect %>
161
+
162
+ source:
163
+
164
+ <%= source.pretty_inspect %>
165
+
166
+ END
167
+ end
160
168
 
161
- # This means we "have" a default since we believe we can use it to make
162
- # one - the actual values will have to be validates at that point.
169
+ # It must be a {Proc} or be frozen
170
+ unless Proc === default || default.frozen?
171
+ raise ArgumentError.new binding.erb <<-END
172
+ Non-proc default values must be frozen
173
+
174
+ Default values that are *not* a {Proc} are shared between *all*
175
+ instances of the prop'd class, and as such *must* be immutable
176
+ (`#frozen? == true`).
177
+
178
+ Found `default`:
179
+
180
+ <%= default.pretty_inspect %>
181
+
182
+ when constructing prop <%= name.inspect %>
183
+ for class <%= defined_in.name %>
184
+ END
185
+ end
186
+
163
187
  @has_default = true
164
-
165
- # And set it.
166
- #
167
- # TODO validate it's something reasonable here?
168
- #
169
- @default_from = default_from
170
- end
188
+ @default = default
189
+ end # #init_default!
171
190
 
172
- end # #initialize
191
+ # end protected
192
+ public
193
+
194
+
195
+ # Instance Methods
196
+ # ============================================================================
197
+
198
+ # Used by the {NRSER::Meta::Props::ClassMethods.prop} "macro" method to
199
+ # determine if it should create a reader method on the propertied class.
200
+ #
201
+ # @return [Boolean]
202
+ # `true` if a reader method should be created for the prop value.
203
+ #
204
+ def create_reader?
205
+ # Always create readers for primary props
206
+ return true if primary?
207
+
208
+ # Don't override methods
209
+ return false if defined_in.instance_methods.include?( name )
210
+
211
+ # Create if {#source} is a {Proc} so it's accessible
212
+ return true if Proc === source
213
+
214
+ # Source is a symbol; only create if it's not the same as the name
215
+ return source != name
216
+ end # #create_reader?
217
+
218
+
219
+ # Used by the {NRSER::Meta::Props::ClassMethods.prop} "macro" method to
220
+ # determine if it should create a writer method on the propertied class.
221
+ #
222
+ # Right now, we don't create writers, but we will probably make them an
223
+ # option in the future, which is why this stub is here.
224
+ #
225
+ # @return [Boolean]
226
+ # Always `false` for the moment.
227
+ #
228
+ def create_writer?
229
+ false
230
+ end # #create_writer?
173
231
 
174
232
 
175
233
  # Full name with class prop was defined in.
@@ -202,8 +260,12 @@ class NRSER::Meta::Props::Prop
202
260
 
203
261
 
204
262
  def default
205
- if default?
206
- @default
263
+ if has_default?
264
+ if Proc === @default
265
+ @default.call
266
+ else
267
+ @default
268
+ end
207
269
  else
208
270
  raise NameError.new NRSER.squish <<-END
209
271
  Prop #{ self } has no default value.
@@ -212,13 +274,9 @@ class NRSER::Meta::Props::Prop
212
274
  end
213
275
 
214
276
 
215
- # @todo Document source? method.
216
- #
217
- # @param [type] arg_name
218
- # @todo Add name param description.
277
+ # Does this property have a source method that it gets it's value from?
219
278
  #
220
- # @return [return_type]
221
- # @todo Document return value.
279
+ # @return [Boolean]
222
280
  #
223
281
  def source?
224
282
  !@source.nil?
@@ -466,7 +524,7 @@ class NRSER::Meta::Props::Prop
466
524
 
467
525
  ERB
468
526
  end
469
-
527
+
470
528
  end # #value_from_data
471
529
 
472
530
 
@@ -16,7 +16,7 @@ module NRSER
16
16
  # @return [Exception]
17
17
  #
18
18
  def squished message
19
- new message.squish
19
+ new NRSER.squish( message )
20
20
  end
21
21
 
22
22
  # Create a new instance from the dedented message.
@@ -28,7 +28,7 @@ module NRSER
28
28
  # @return [Exception]
29
29
  #
30
30
  def dedented message
31
- new message.dedent
31
+ new NRSER.dedent( message )
32
32
  end
33
33
 
34
34
  end # refine Exception.singleton_class