Comments (7)
@flash-gordon v1.3.0 has been released
from dry-initializer.
note that atm we're using v0.11 that doesn't have UNDEFINED
s.
from dry-initializer.
@flash-gordon thank you! I think adding that config is a good idea.
I think it could work like:
# current behaviour with UNDEFINED assigned and checked in readers
extend Dry::Initializer
# don't use UNDEFINED (assign `nil` instead)
extend Dry::Initializer[undefined: false]
I should think a bit more about edge cases (like setting default values in case of nil
was assigned). I thihk I could add in a week or so.
from dry-initializer.
Concerning v0.11
... actually, it does use UNDEFINED
:
from dry-initializer.
ahh, yes, I meant undefined
in readers :)
from dry-initializer.
The only edge case I found is following
By design, type constraint/coercion provides a sort of a "hard" contract.
It gives garancy that an attribute is either left UNDEFINED
or satisfies the constraint. For this reason a constraint is applied to both the explicitly assigned value, and result of default.
class Foo
extend Dry::Initializer
option :bar, proc(&:to_i), default: proc { "1" }
option :baz, proc(&:to_i), optional: true
end
foo = Foo.new(bar: 3, baz: nil)
foo.instance_variable_get(:@bar) # => 3
foo.instance_variable_get(:@baz) # => 0
foo = Foo.new
foo.instance_variable_get(:@bar) # => 1
foo.instance_variable_get(:@baz) # => UNDEFINED
The latest example is special in a sense it only marks missing value. If you try to assign UNDEFINED either explicitly, or implicitly (via defaults), it will be sent to coercer and (hopefully) raise an exception.
class Foo
extend Dry::Initializer
option :baz, proc(&:to_i), optional: true
end
foo = Foo.new(baz: Dry::Initializer::UNDEFINED)
# => BOOM! 'cause UNDEFINED has no #to_i
foo = Foo.new
foo.instance_variable_get(:@baz) # => nil
TBH, it is not that exceptional due to #to_s
etc., but the core idea is here.
The code for the initializer is the following
def __initialize__(__options__ = {})
# ... instantiating @__options__
@bar = __coercers__[:'option_bar'].call(__options__.fetch(:'bar') { instance_exec(&__defaults__[:'option_bar']) })
@baz = __options__.key?(:'baz') ? __coercers__[:'option_baz'].call(__options__.fetch(:'baz')) : Dry::Initializer::UNDEFINED
# ... assigning @__options__
end
In case when UNDEFINED
dropped in favour of nil
, the behaviour changes so that a constraint becomes "softer" and less consistent.
class Foo
extend Dry::Initializer
option :bar, optional: true
option :baz, proc(&:to_i), optional: true
end
foo = Foo.new(bar: nil, baz: nil)
foo.instance_variable_get(:@bar) # => nil
foo.instance_variable_get(:@baz) # => 0
foo = Foo.new
foo.instance_variable_get(:@bar) # => nil
foo.instance_variable_get(:@baz) # => nil
This becomes a bit confusing to me. For baz
the nil
marks a case no assignment was made. But it is not universal -- for bar
nil
is... just a nil
.
This time I'm wondering whether this simplification worth it. Maybe we should left UNDEFINED
assigned (just like in v0.11), but not hidden in a reader.
class Foo
extend Dry::Initializer
option :bar, optional: true
end
foo = Foo.new
foo.instance_variable_get(:@bar) # => Dry::Initializer::UNDEFINED
foo.bar # => nil
class Qux
extend Dry::Initializer[hide_undefined: false] # no check for UNDEFINED
option :bar, optional: true
end
qux = Qux.new
qux.instance_variable_get(:@bar) # => Dry::Initializer::UNDEFINED
qux.bar # => Dry::Initializer::UNDEFINED
from dry-initializer.
Well, I dunno, from the rom
POV we don't need undefined
because it doesn't help us, it requires extra checks for undefined
where nil?
is enough. Hence we're using default: proc { nil }
for having nil
s everywhere and the need of wrapping nil
with a proc
is also annoying a bit.
from dry-initializer.
Related Issues (20)
- Overriding of dry-container dependencies creates unexpected behaviour HOT 1
- Work out semver-appropriate way to release now-yanked 2.6.0 changes [was: "2.6.0 broke public API"] HOT 1
- 2.5.0 doesn't have a changelog entry HOT 6
- Tokenize hash params HOT 2
- dry-initializer relies on Symbol#to_proc#arity being -1 HOT 1
- Non-lazy defaults are harder to use with specs HOT 3
- [Feature Request] Option to skip type checking in certain cases HOT 3
- Getters provide inconsistent results in debugging HOT 6
- Does the check for unknown positional parameters work? HOT 4
- Option "as" feature not working HOT 2
- Deprecation warning with Ruby 2.7: Using the last argument as keyword parameters is deprecated HOT 4
- Update cops from Rubocop HOT 1
- Ruby 2.7 warning HOT 3
- Upgrading to ruby 3 causes the initializer to unproperly handle auto-injected args HOT 2
- Feature - method signatures HOT 2
- [Security] Workflow ci.yml is using vulnerable action actions/checkout
- Ruby 3 support HOT 1
- ordering of option declarations should not prohibit forward reference in default procs HOT 6
- Why is downcase applied on target parameter / option? HOT 3
- Default value only if not nil HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dry-initializer.