Skip to content

Commit

Permalink
Type refactor (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcandre authored and zverok committed Dec 9, 2018
1 parent 510f4d6 commit c4d6640
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 30 deletions.
4 changes: 2 additions & 2 deletions lib/tlaw/params/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Base
def initialize(name, **options)
@name = name
@options = options
@type = Type.parse(options)
@type = Type.parse(**options)
@options[:desc] ||= @options[:description]
@options[:desc]&.gsub!(/\n( *)/, "\n ")
@formatter = make_formatter
Expand Down Expand Up @@ -62,7 +62,7 @@ def describe
name,
("[#{doc_type}]" if doc_type),
description,
("\n Possible values: #{type.values.map(&:inspect).join(', ')}" if @options[:enum]),
("\n Possible values: #{type.possible_values}" if type.respond_to?(:possible_values)),
("(default = #{default.inspect})" if default)
].compact
.join(' ')
Expand Down
48 changes: 20 additions & 28 deletions lib/tlaw/params/type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@ module Params
class Type
attr_reader :type

def self.parse(options)
type = options[:type]

def self.parse(type: nil, enum: nil, **)
case type
when nil
options[:enum] ? EnumType.new(options[:enum]) : Type.new(nil)
enum ? EnumType.new(enum) : Type.new(nil)
when Class
ClassType.new(type)
when Symbol
DuckType.new(type)
when Hash
EnumType.new(type)
else
fail ArgumenError, "Undefined type #{type}"
fail ArgumentError, "Undefined type #{type}"
end
end

Expand All @@ -30,28 +28,26 @@ def to_doc_type
end

def convert(value)
validate(value) && _convert(value)
if (err = validation_error(value))
fail Nonconvertible,
"#{self} can't convert #{value.inspect}: #{err}"
end
_convert(value)
end

def validate(_value)
true
def validation_error(_value)
nil
end

def _convert(value)
value
end

def nonconvertible!(value, reason)
fail Nonconvertible,
"#{self} can't convert #{value.inspect}: #{reason}"
end
end

# @private
class ClassType < Type
def validate(value)
value.is_a?(type) or
nonconvertible!(value, "not an instance of #{type}")
def validation_error(value)
"not an instance of #{type}" unless value.is_a?(type)
end

def _convert(value)
Expand All @@ -69,9 +65,8 @@ def _convert(value)
value.send(type)
end

def validate(value)
value.respond_to?(type) or
nonconvertible!(value, "not responding to #{type}")
def validation_error(value)
"not responding to #{type}" unless value.respond_to?(type)
end

def to_doc_type
Expand All @@ -82,7 +77,7 @@ def to_doc_type
# @private
class EnumType < Type
def initialize(enum)
@type =
super(
case enum
when Hash
enum
Expand All @@ -91,18 +86,15 @@ def initialize(enum)
else
fail ArgumentError, "Unparseable enum: #{enum.inspect}"
end
)
end

def values
type.keys
def possible_values
type.keys.map(&:inspect).join(', ')
end

def validate(value)
type.key?(value) or
nonconvertible!(
value,
"is not one of #{type.keys.map(&:inspect).join(', ')}"
)
def validation_error(value)
"is not one of #{possible_values}" unless type.key?(value)
end

def _convert(value)
Expand Down
12 changes: 12 additions & 0 deletions spec/tlaw/param_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ module Params
end
end

describe '#type' do
it 'raises an ArgumentError on bad argument' do
expect { described_class.new(:p, type: 'hello') }.to raise_error(ArgumentError, 'Undefined type hello')
end
end

describe '#describe' do
subject { param.describe }

Expand Down Expand Up @@ -200,6 +206,12 @@ module Params
it { is_expected.to include('Possible values: true, false') }
end

context 'hash via type' do
let(:param) { described_class.new(:p, type: {true => 'foo', false => 'bar'}) }

it { is_expected.to include('Possible values: true, false') }
end

context 'other enumerable' do
let(:param) { described_class.new(:p, enum: %w[foo bar]) }

Expand Down

0 comments on commit c4d6640

Please sign in to comment.