0.0
No commit activity in last 3 years
No release in over 3 years
A lightweight library to define object conversion methods/modules.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

 Project Readme

PowerConverter

Gem Version Build Status Code Climate Test Coverage Documentation Status APACHE 2 License

About

PowerConverter exposes a means for defining a named conversion method.

Brief Example

PowerConverter.define_conversion_for(:boolean) do |input|
  case input
  when false, 0, '0', /\A(false|no)\Z/i, nil then false
  when String
    input.empty? ? nil : true
  else
    true
  end
end

expect(PowerConverter.convert('no', to: :boolean)).to eq(false)
expect(PowerConverter.convert('yes', to: :boolean)).to eq(true)
expect { PowerConverter.convert('', to: :boolean) }.to raise_error(PowerConverter::ConversionError)

Details

What is a conversion method?

A well-established Ruby idiom for methods which "do the right thing" to convery any reasonable input value into a desired class.

http://devblog.avdi.org/2012/05/07/a-ruby-conversion-idiom/

Why conversion methods?

Because software is all about addressing a mapping problem. In my experience using conversion methods has provided a means for easing the movement across application design boundaries.

Why use the PowerConverter gem?

Excellent question.

The short-answer is consistency. PowerConverter helps you compose conversions that have a common form.

The longer-answer is again related to consistency. By using a common mechanism for definition, I'm hoping to reduce the nuanced variations that come from crafting conversions. They all have a very similar shape, and I'd like to provide tooling to help keep that shape.

I would much rather focus on other concepts than "is this conversion method similar enough to its sibling conversion methods?"

In other words, relying on a common interface for defining a conversion method reduces the number surprises when interacting with conversion methods.

Usage

Name and define conversions via a block.

PowerConverter.define_conversion_for(:always_true) { true }
PowerConverter.define_conversion_for(:always_nil) { nil }
PowerConverter.define_conversion_for(:boolean) { |value| !!value }

Call the conversions via a couple of methods:

PowerConverter.convert(nil, to: :always_true)
# or
PowerConverter.convert_to_always_true(nil)

When you call a conversion, if the conversion block evaluates to nil, PowerConverter will fail with a PowerConverter::ConversionError exception.

assert_raises(PowerConverter::ConversionError) { PowerConverter.convert(true, to: :always_nil) }

If you call the conversion and pass a block, the block will be the fallback for an evaluated nil.

assert_equal('FALLBACK', PowerConverter.convert(true, to: :always_nil) { 'FALLBACK'} )

If the object you are attempting to convert responds to the to_<conversion_name> method, that method will be called.

Thing = Struct.new(:to_always_nil)
thing = Thing.new("result of to_always_nil")
assert_equal("result of to_always_nil", PowerConverter.convert(thing, to: :always_nil))

You can also declare an alias for a registered PowerConverter.

PowerConverter.define_alias(:true_or_false, is_alias_of: :boolean)
PowerConverter.convert("Hello", to: :boolean)

At times, a conversion may need additional information to be successful.

PowerConverter.define_conversion_for(:user_action) do |input, user|
  case input
  when String, Symbol then user.actions.find_by(name: input)
  when Model::Action
    input.user == user ? input : nil
  end
end

PowerConverter.convert('start', to: :user_action, scope: a_user)

TODO

  • Write about module declaration