dry-rb/dry-initializer

View on GitHub
docsite/source/optionals-and-defaults.html.md

Summary

Maintainability
Test Coverage
---
title: Optional Attributes and Default Values
layout: gem-single
name: dry-initializer
---

By default both params and options are mandatory. Use `:default` key to make them optional:

```ruby
require 'dry-initializer'

class User
  extend Dry::Initializer

  param  :name,  default: proc { 'Unknown user' }
  option :email, default: proc { 'unknown@example.com' }
  option :phone, optional: true
end

user = User.new
user.name  # => 'Unknown user'
user.email # => 'unknown@example.com'
user.phone # => Dry::Initializer::UNDEFINED

user = User.new 'Vladimir', email: 'vladimir@example.com', phone: '71234567788'
user.name  # => 'Vladimir'
user.email # => 'vladimir@example.com'
user.phone # => '71234567788'
```

You cannot define required **parameter** after optional one. The following example raises `SyntaxError` exception:

```ruby
require 'dry-initializer'

class User
  extend Dry::Initializer

  param :name, default: proc { 'Unknown name' }
  param :email # => #<SyntaxError ...>
end
```

You should assign `nil` value explicitly. Otherwise an instance variable it will be left undefined. In both cases attribute reader method will return `nil`.

```ruby
require 'dry-initializer'

class User
  extend Dry::Initializer

  param  :name
  option :email, optional: true
end

user = User.new 'Andrew'
user.email # => nil
user.instance_variable_get :@email
# => Dry::Initializer::UNDEFINED

user = User.new 'Andrew', email: nil
user.email # => nil
user.instance_variable_get :@email
# => nil
```

You can also set `nil` as a default value:

```ruby
require 'dry-initializer'

class User
  extend Dry::Initializer

  param  :name
  option :email, default: proc { nil }
end

user = User.new 'Andrew'
user.email # => nil
user.instance_variable_get :@email
# => nil
```

You **must** wrap default values into procs.

If you need to **assign** proc as a default value, wrap it to another one:

```ruby
require 'dry-initializer'

class User
  extend Dry::Initializer

  param :name_proc, default: proc { proc { 'Unknown user' } }
end

user = User.new
user.name_proc.call # => 'Unknown user'
```

Proc will be executed in a scope of new instance. You can refer to other arguments:

```ruby
require 'dry-initializer'

class User
  extend Dry::Initializer

  param :name
  param :email, default: proc { "#{name.downcase}@example.com" }
end

user = User.new 'Andrew'
user.email # => 'andrew@example.com'
```

**Warning**: when using lambdas instead of procs, don't forget an argument, required by [instance_eval][instance_eval] (you can skip in in a proc).

```ruby
require 'dry-initializer'

class User
  extend Dry::Initializer

  param :name, default: -> (obj) { 'Dude' }
end
```

[instance_eval]: http://ruby-doc.org/core-2.2.0/BasicObject.html#method-i-instance_eval