nrser 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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