hecks 1.0.0 → 1.0.2

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.
@@ -38,8 +38,8 @@ module Hecks
38
38
  end
39
39
 
40
40
  def type_name = @value_object.hecks_name
41
- def [](field) = @fields[field.to_sym]
42
- def key?(field) = @fields.key?(field.to_sym)
41
+ def [](field) = @fields[resolve_field(field)]
42
+ def key?(field) = @fields.key?(resolve_field(field))
43
43
  def to_h = @fields.transform_values { |value| self.class.materialize(value) }
44
44
  def to_json(*) = JSON.generate(to_h)
45
45
 
@@ -48,7 +48,7 @@ module Hecks
48
48
  end
49
49
 
50
50
  def with(field, value)
51
- self.class.build(@value_object, @fields.merge(field.to_sym => value))
51
+ self.class.build(@value_object, @fields.merge(resolve_field(field) => value))
52
52
  end
53
53
 
54
54
  def self.materialize(value)
@@ -114,11 +114,61 @@ module Hecks
114
114
  def method_missing(name, *args)
115
115
  return @fields[name] if @fields.key?(name)
116
116
 
117
+ # THE LANGUAGE RULE, not a convenience: ANY value object with
118
+ # exactly one declared attribute answers `.value`, whatever that
119
+ # attribute is actually named — a single-attribute value object
120
+ # is a NAME for a scalar, not a genuine group
121
+ # ([[feedback_name_the_scalar_field]], `Behaviour::ValueObject#
122
+ # sole_attribute`), so `money.value` reads `Money`'s own `amount`
123
+ # exactly as `label.value` reads a shorthand-declared `value`.
124
+ # AFTER the real-field lookup above, on purpose: a field
125
+ # literally named `value` is already answered there (and IS the
126
+ # sole attribute whenever the count is one), so this branch only
127
+ # ever aliases, never shadows. A MULTI-attribute value object
128
+ # keeps its NoMethodError — `sole_attribute` answers nil for it,
129
+ # and falling through to `super` is exactly the refusal it
130
+ # always gave: with two or more fields there is no single value
131
+ # `.value` could honestly mean.
132
+ if name == :value
133
+ sole = @value_object.sole_attribute
134
+ return @fields[sole.name] if sole
135
+ end
136
+
117
137
  super
118
138
  end
119
139
 
120
140
  def respond_to_missing?(name, include_private = false)
121
- @fields.key?(name) || super
141
+ return true if @fields.key?(name)
142
+ return true if name == :value && @value_object.sole_attribute
143
+
144
+ super
145
+ end
146
+
147
+ private
148
+
149
+ # THE `.value` ALIAS FOR INDEXED ACCESS — the same language rule
150
+ # `method_missing` above enforces for method reads, applied to
151
+ # `[]`/`key?`/`with`: `:value` names a single-attribute value
152
+ # object's sole field whatever that field is actually called. A
153
+ # REAL key always wins first (a field literally named `value` is
154
+ # its own answer, and is the sole attribute anyway whenever the
155
+ # count is one), so this only ever resolves a `:value` that would
156
+ # otherwise MISS — it can never redirect a genuine field read.
157
+ # `with(:value, x)` in particular NEEDS this: merging a literal
158
+ # `:value` key beside a sole field named `amount` would build a
159
+ # two-key hash for a one-field shape and be refused (or worse,
160
+ # stored) downstream — aliasing at the merge is what keeps the
161
+ # write half of the rule as true as the read half.
162
+ def resolve_field(field)
163
+ sym = field.to_sym
164
+ return sym if @fields.key?(sym)
165
+
166
+ if sym == :value
167
+ sole = @value_object.sole_attribute
168
+ return sole.name if sole
169
+ end
170
+
171
+ sym
122
172
  end
123
173
  end
124
174
  end
data/lib/hecks/version.rb CHANGED
@@ -12,5 +12,5 @@ module Hecks
12
12
  # it there, or even in the consuming Gemfile, never closed the gap,
13
13
  # because gemspec evaluation happens before anything Bundler
14
14
  # resolves is actually loadable yet.
15
- VERSION = "1.0.0"
15
+ VERSION = "1.0.2"
16
16
  end
data/lib/hecks.rb CHANGED
@@ -100,7 +100,27 @@ module Hecks
100
100
  end
101
101
 
102
102
  def hecksagon(name, &block) = collect(:add_hecksagon, Bluebook::DSL::HecksagonBuilder.build(name, &block))
103
- def port(name, &block) = collect(:add_port, Bluebook::DSL::PortBuilder.build(name, &block))
103
+ # REPOINTED TO DomainPortBuilder the migration DomainPort's own
104
+ # class comment names as its goal, now landed for the top-level
105
+ # `.port` file callers too (the aggregate-scoped `Thing.port(...)`,
106
+ # binding_proxy.rb, already went through this builder). Every real
107
+ # `.port` file only ever spells `verb`/`signal` (no `.port` file
108
+ # declares operations — that's DomainPort's own newer shape), and
109
+ # DomainPortBuilder's own bare-verb branch produces the exact same
110
+ # `Port` object PortBuilder itself did (dsl_spec.rb's own byte-
111
+ # identity check) — a pure repoint, no behavior change for any
112
+ # existing caller reading `.verb`/`.signal` off what comes back.
113
+ #
114
+ # `legacy_bare_port: true` — the ONE real semantic gap this repoint
115
+ # would otherwise open: `PortBuilder#build` never refused a
116
+ # completely empty build (no verb, no signal even), a real shape
117
+ # dsl_spec.rb's own "a port" tests exercise (`signal`-only, no
118
+ # `verb`). `DomainPortBuilder`'s own "declares no verb and no
119
+ # operations" refusal is real and correct for its OTHER two callers
120
+ # (`BindingProxy#port`, `HecksagonBuilder#port_impl`) — only this,
121
+ # the literal top-level `.port` file entry point, keeps the older,
122
+ # looser rule (see `DomainPortBuilder#initialize`'s own comment).
123
+ def port(name, &block) = collect(:add_port, Bluebook::DSL::DomainPortBuilder.build(name, legacy_bare_port: true, &block))
104
124
  def adapter(name, &block) = collect(:add_adapter, Bluebook::DSL::AdapterBuilder.build(name, &block))
105
125
  def world(name, &block) = collect(:add_world, Bluebook::DSL::WorldBuilder.build(name, &block))
106
126
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hecks
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Young
@@ -140,6 +140,7 @@ files:
140
140
  - lib/hecks/bluebook/dsl/world_builder.rb
141
141
  - lib/hecks/bluebook/entity.rb
142
142
  - lib/hecks/bluebook/expression.rb
143
+ - lib/hecks/bluebook/expression/ast_json.rb
143
144
  - lib/hecks/bluebook/expression/canonical_form.rb
144
145
  - lib/hecks/bluebook/expression/evaluator.rb
145
146
  - lib/hecks/bluebook/expression/projection.json
@@ -427,6 +428,8 @@ licenses:
427
428
  metadata:
428
429
  allowed_push_host: https://rubygems.org
429
430
  source_code_uri: https://github.com/heckslabs/hecks
431
+ changelog_uri: https://github.com/heckslabs/hecks/blob/main/CHANGELOG.md
432
+ documentation_uri: https://rubydoc.info/gems/hecks
430
433
  post_install_message:
431
434
  rdoc_options: []
432
435
  require_paths: