Module: Punctuated::Options

Defined in:
lib/punctuated/options.rb

Overview

Centralises strict option validation and string/symbol indifference for every public method.

Class Method Summary collapse

Class Method Details

.enum(value, allowed:, label:, allow_nil: false) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/punctuated/options.rb', line 38

def enum(value, allowed:, label:, allow_nil: false)
	return nil if value.nil? && allow_nil

	normalised = if value.is_a?(String)
		value.to_sym
	elsif value.is_a?(Symbol)
		value
	end
	unless allowed.include?(normalised)
		raise ArgumentError, "invalid #{label}: #{value.inspect}"
	end

	normalised
end

.hash(positional, keywords, allowed:, label: "options") ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/punctuated/options.rb', line 8

def hash(positional, keywords, allowed:, label: "options")
	unless positional.nil? || positional.is_a?(Hash)
		raise ArgumentError, "#{label} must be a Hash"
	end

	normalised = {}
	[positional || {}, keywords || {}].each do |source|
		source.each do |key, value|
			normalised_key = key(key)
			unless allowed.include?(normalised_key)
				raise ArgumentError, "unknown #{label} key: #{key.inspect}"
			end
			if normalised.key?(normalised_key)
				raise ArgumentError, "duplicate #{label} key: #{normalised_key.inspect}"
			end

			normalised[normalised_key] = value
		end
	end

	normalised
end

.key(value) ⇒ Object

Raises:

  • (ArgumentError)


31
32
33
34
35
36
# File 'lib/punctuated/options.rb', line 31

def key(value)
	return value if value.is_a?(Symbol)
	return value.to_sym if value.is_a?(String)

	raise ArgumentError, "option keys must be Strings or Symbols"
end

.placement(value, allow_nil: true) ⇒ Object



53
54
55
# File 'lib/punctuated/options.rb', line 53

def placement(value, allow_nil: true)
	enum(value, allowed: [:inside, :outside], label: "placement", allow_nil: allow_nil)
end

.side(value) ⇒ Object



57
58
59
# File 'lib/punctuated/options.rb', line 57

def side(value)
	enum(value, allowed: [:start, :end], label: "side")
end

.sides(value, label:, side: nil, &validator) ⇒ Object

Expands shorthand values to start/end pairs, optionally directing shorthand to one implicit side.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/punctuated/options.rb', line 62

def sides(value, label:, side: nil, &validator)
	implicit_side = side.nil? ? nil : self.side(side)
	values = value.is_a?(Array) ? value.dup : [value]
	case values.length
	when 1
		values = case implicit_side
		when :start
			[values.first, nil]
		when :end
			[nil, values.first]
		else
			[values.first, values.first]
		end
	when 2
		# Already in the required two-sided form.
	else
		raise ArgumentError, "#{label} must contain one or two elements"
	end

	values.map(&validator)
end