Module: Errgonomic::Rails

Defined in:
lib/errgonomic/rails.rb,
lib/errgonomic/rails/active_record_optional.rb,
lib/errgonomic/rails/active_record_optional.rb,
lib/errgonomic/rails/active_record_delegate_optional.rb,
lib/errgonomic/rails/active_record_optional.rb,
lib/errgonomic/rails/active_record_optional.rb,
lib/errgonomic/rails/active_record_optional.rb,
lib/errgonomic/rails/active_record_optional.rb,
lib/errgonomic/rails/active_record_optional.rb,
lib/errgonomic/rails/active_record_optional.rb,
lib/errgonomic/rails/active_record_optional.rb

Overview

Slightly more convenient access to the setup functions: Errgonomic::Rails.setup_before and Errgonomic::Rails.setup_after

Defined Under Namespace

Modules: ActionViewTagValue, ActiveModelAttributeDefault, ActiveModelAttributeWrite, ActiveRecordBulkWrite, ActiveRecordDelegateOptional, ActiveRecordFind, ActiveRecordOptional, ActiveRecordPredicateBuilder, ActiveRecordQuoting, ActiveRecordRelationFind, ActiveRecordSingularAssociationWriter

Class Method Summary collapse

Class Method Details

.setup_afterObject

Models opt in to ActiveRecordOptional individually via include Errgonomic::Rails::ActiveRecordOptional.



22
# File 'lib/errgonomic/rails.rb', line 22

def self.setup_after; end

.setup_beforeObject

We provide helper class methods, like delegate_optional, which need to be included into ActiveRecord::Base before any models are evaluated.



16
17
18
# File 'lib/errgonomic/rails.rb', line 16

def self.setup_before
  ActiveRecord::Base.include(Errgonomic::Rails::ActiveRecordDelegateOptional)
end

.unwrap_option(value) ⇒ Object

Take the value inside an Option, and a None as nil, where the boundary takes one value: an attribute is a single typed field, so a collection that happens to hold an Option is that collection. A bare variant name is refused here, since a boolean column would cast it to true.

Examples:

Errgonomic::Rails.unwrap_option(Some(1)) # => 1
Errgonomic::Rails.unwrap_option(None()) # => nil
Errgonomic::Rails.unwrap_option([Some(1)]) # => [Some(1)]
Errgonomic::Rails.unwrap_option(None) # => raise Errgonomic::SerializeError, "bare None names a variant for a pattern, not a value; build one with parentheses"


564
565
566
567
# File 'lib/errgonomic/rails/active_record_optional.rb', line 564

def self.unwrap_option(value)
  value.refuse! if value.is_a?(Errgonomic::VariantName)
  value.is_a?(Errgonomic::Option::Any) ? value.unwrap_or(nil) : value
end

.unwrap_option_default(default) ⇒ Object

A declared default that is a Proc is not a value yet: ActiveModel calls it with no arguments each time a record is built. Wrap it rather than unwrap it, so what it returns meets the type where a literal default already does.

Examples:

Errgonomic::Rails.unwrap_option_default(Some(1)) # => 1
Errgonomic::Rails.unwrap_option_default(-> { Some(1) }).call # => 1


612
613
614
615
616
# File 'lib/errgonomic/rails/active_record_optional.rb', line 612

def self.unwrap_option_default(default)
  return unwrap_option(default) unless default.is_a?(Proc)

  -> { unwrap_option(default.call) }
end

.unwrap_option_rows(rows) ⇒ Object

Unwrap each value of each row, where the boundary takes a list of rows. A list holding no Option is handed back rather than copied.

Examples:

Errgonomic::Rails.unwrap_option_rows([{ title: Some('x') }]) # => [{ title: 'x' }]
plain = [{ title: 'x' }]
Errgonomic::Rails.unwrap_option_rows(plain).equal?(plain) # => true


592
593
594
595
596
# File 'lib/errgonomic/rails/active_record_optional.rb', line 592

def self.unwrap_option_rows(rows)
  return rows unless rows.any? { |row| row.is_a?(Hash) && row.each_value.any? { |v| unwrapped_at_boundary?(v) } }

  rows.map { |row| row.is_a?(Hash) ? unwrap_option_values(row) : row }
end

.unwrap_option_values(hash) ⇒ Object

Unwrap each value of a hash one layer, where the boundary takes a row or a set of conditions rather than a single value. A nested structure is the caller's own, and is left as it is. A hash holding no Option is handed back rather than copied: every write passes here, and most carry none.

Examples:

Errgonomic::Rails.unwrap_option_values(title: Some('x'), body: None()) # => { title: 'x', body: nil }
plain = { title: 'x' }
Errgonomic::Rails.unwrap_option_values(plain).equal?(plain) # => true


579
580
581
582
583
# File 'lib/errgonomic/rails/active_record_optional.rb', line 579

def self.unwrap_option_values(hash)
  return hash unless hash.each_value.any? { |value| unwrapped_at_boundary?(value) }

  hash.transform_values { |value| unwrap_option(value) }
end

.unwrap_options(value) ⇒ Object

Take the value inside an Option at a boundary into ActiveRecord, and a None as nil, reaching one level into an array so a list of Options passes as a list of values.

Examples:

Errgonomic::Rails.unwrap_options(Some(1)) # => 1
Errgonomic::Rails.unwrap_options(None()) # => nil
Errgonomic::Rails.unwrap_options([Some(1), None()]) # => [1, nil]
Errgonomic::Rails.unwrap_options(1) # => 1


543
544
545
546
547
548
549
550
551
552
# File 'lib/errgonomic/rails/active_record_optional.rb', line 543

def self.unwrap_options(value)
  case value
  when Errgonomic::Option::Any, Errgonomic::VariantName
    unwrap_option(value)
  when Array
    value.any? { |v| unwrapped_at_boundary?(v) } ? value.map { |v| unwrap_options(v) } : value
  else
    value
  end
end

.unwrapped_at_boundary?(value) ⇒ Boolean

An Option, or a bare variant name, which a boundary refuses rather than let a column type cast it.

Returns:

  • (Boolean)


600
601
602
# File 'lib/errgonomic/rails/active_record_optional.rb', line 600

def self.unwrapped_at_boundary?(value)
  value.is_a?(Errgonomic::Option::Any) || value.is_a?(Errgonomic::VariantName)
end