mixture 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +35 -4
- data/Gemfile +2 -1
- data/Rakefile +1 -0
- data/lib/mixture/attribute.rb +1 -0
- data/lib/mixture/attribute_list.rb +49 -2
- data/lib/mixture/coerce/array.rb +1 -0
- data/lib/mixture/coerce/base.rb +9 -7
- data/lib/mixture/coerce/boolean.rb +1 -0
- data/lib/mixture/coerce/class.rb +5 -2
- data/lib/mixture/coerce/date.rb +1 -0
- data/lib/mixture/coerce/datetime.rb +1 -0
- data/lib/mixture/coerce/float.rb +1 -0
- data/lib/mixture/coerce/hash.rb +1 -0
- data/lib/mixture/coerce/integer.rb +1 -0
- data/lib/mixture/coerce/nil.rb +1 -0
- data/lib/mixture/coerce/object.rb +3 -5
- data/lib/mixture/coerce/range.rb +1 -0
- data/lib/mixture/coerce/rational.rb +1 -0
- data/lib/mixture/coerce/set.rb +1 -0
- data/lib/mixture/coerce/string.rb +1 -0
- data/lib/mixture/coerce/symbol.rb +1 -0
- data/lib/mixture/coerce/time.rb +1 -0
- data/lib/mixture/coerce.rb +3 -4
- data/lib/mixture/errors.rb +1 -0
- data/lib/mixture/extensions/attributable.rb +11 -3
- data/lib/mixture/extensions/coercable.rb +1 -0
- data/lib/mixture/extensions/hashable.rb +4 -4
- data/lib/mixture/extensions/validatable.rb +1 -0
- data/lib/mixture/extensions.rb +1 -0
- data/lib/mixture/model.rb +1 -0
- data/lib/mixture/types/access.rb +2 -1
- data/lib/mixture/types/array.rb +1 -0
- data/lib/mixture/types/boolean.rb +1 -0
- data/lib/mixture/types/class.rb +1 -0
- data/lib/mixture/types/collection.rb +1 -0
- data/lib/mixture/types/date.rb +1 -0
- data/lib/mixture/types/datetime.rb +1 -0
- data/lib/mixture/types/enumerable.rb +1 -0
- data/lib/mixture/types/float.rb +1 -0
- data/lib/mixture/types/hash.rb +1 -0
- data/lib/mixture/types/integer.rb +1 -0
- data/lib/mixture/types/nil.rb +1 -0
- data/lib/mixture/types/numeric.rb +1 -0
- data/lib/mixture/types/object.rb +1 -0
- data/lib/mixture/types/range.rb +1 -0
- data/lib/mixture/types/rational.rb +1 -0
- data/lib/mixture/types/set.rb +1 -0
- data/lib/mixture/types/string.rb +1 -0
- data/lib/mixture/types/symbol.rb +1 -0
- data/lib/mixture/types/time.rb +1 -0
- data/lib/mixture/types/type.rb +1 -0
- data/lib/mixture/types.rb +1 -0
- data/lib/mixture/validate/base.rb +2 -1
- data/lib/mixture/validate/exclusion.rb +1 -0
- data/lib/mixture/validate/inclusion.rb +1 -0
- data/lib/mixture/validate/length.rb +4 -6
- data/lib/mixture/validate/match.rb +2 -1
- data/lib/mixture/validate/presence.rb +2 -1
- data/lib/mixture/validate.rb +1 -0
- data/lib/mixture/version.rb +2 -1
- data/lib/mixture.rb +1 -0
- data/mixture.gemspec +4 -3
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c822237c85384a60d89edebd9cc47e992741047
|
4
|
+
data.tar.gz: e5a9cecb2887162a042bed5b32dc99331159f8f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6179364b8124dae17d3070aa96ac5ec1033665cba7b73db39220e8dbb1486e2a2fb2310550ffa10dcfab72cfc48df29d7b7797cfcd92992b8c62513b50eb38b4
|
7
|
+
data.tar.gz: 5cf47b98592aaeeda5d8732f797ebe36703406e860b6fab245e32a498d1d2e43da0ca75bf1ff8e24f8ee5da878db4d6121fd59a4cdefe4aa06606f563e5d7806
|
data/.rubocop.yml
CHANGED
@@ -1,9 +1,40 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.3
|
3
|
+
|
4
|
+
Metrics/LineLength:
|
5
|
+
Enabled: false
|
6
|
+
Metrics/MethodLength:
|
7
|
+
Max: 15
|
8
|
+
Metrics/BlockLength:
|
9
|
+
Exclude:
|
10
|
+
- 'spec/*.rb'
|
11
|
+
- 'spec/**/*.rb'
|
12
|
+
Metrics/AbcSize:
|
13
|
+
Max: 25
|
14
|
+
|
15
|
+
Style/AlignParameters:
|
16
|
+
EnforcedStyle: with_fixed_indentation
|
17
|
+
Style/SignalException:
|
18
|
+
EnforcedStyle: only_fail
|
19
|
+
Style/AccessModifierIndentation:
|
20
|
+
EnforcedStyle: outdent
|
21
|
+
Style/Documentation:
|
22
|
+
Enabled: false
|
3
23
|
Style/Encoding:
|
4
24
|
Enabled: true
|
25
|
+
EnforcedStyle: always
|
5
26
|
AutoCorrectEncodingComment: "# encoding: utf-8\n"
|
6
27
|
Style/RegexpLiteral:
|
7
28
|
EnforcedStyle: mixed
|
8
|
-
|
9
|
-
|
29
|
+
Style/StringLiterals:
|
30
|
+
EnforcedStyle: double_quotes
|
31
|
+
Style/AlignHash:
|
32
|
+
EnforcedLastArgumentHashStyle: ignore_implicit
|
33
|
+
Style/AlignArray:
|
34
|
+
Enabled: false
|
35
|
+
Style/IndentArray:
|
36
|
+
Enabled: false
|
37
|
+
Style/Alias:
|
38
|
+
EnforcedStyle: prefer_alias_method
|
39
|
+
Style/ParallelAssignment:
|
40
|
+
Enabled: false
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/lib/mixture/attribute.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "set"
|
4
5
|
require "forwardable"
|
@@ -13,7 +14,36 @@ module Mixture
|
|
13
14
|
# If it quacks like a duck...
|
14
15
|
include Comparable
|
15
16
|
# Then it must be a duck.
|
16
|
-
delegate [
|
17
|
+
delegate [:<=>, :[]=, :to_h] => :@list
|
18
|
+
|
19
|
+
# @!method fetch(key, value = Undefined, &block)
|
20
|
+
# Fetches the given key from the attribute list. If the current attribute
|
21
|
+
# list does not have the key, it passes it up to the parent, if there is
|
22
|
+
# one. If there is no parent, it behaves as normal.
|
23
|
+
#
|
24
|
+
# @param key [::Symbol]
|
25
|
+
# @param value [::Object]
|
26
|
+
# @return [Attribute]
|
27
|
+
# @!method [](key)
|
28
|
+
# Looks up the given key. If the current attribute list does not have the
|
29
|
+
# key, it passes it up to the parent, if there is one. Otherwise, it
|
30
|
+
# returns the default value for the list (`nil`).
|
31
|
+
#
|
32
|
+
# @param key [::Symbol]
|
33
|
+
# @return [Attribute]
|
34
|
+
# @!method key?(key)
|
35
|
+
# Returns if the attribute exists. If it doesn't exist on this list,
|
36
|
+
# it passes it up to the parent.
|
37
|
+
#
|
38
|
+
# @param key [::Symbol]
|
39
|
+
# @return [::Boolean]
|
40
|
+
# @!method each(&block)
|
41
|
+
# Iterates over the attribute list. If there is a parent, the current
|
42
|
+
# attribute list is merged into the parent, then iterated over; otherwise,
|
43
|
+
# it iterates over the current.
|
44
|
+
#
|
45
|
+
# @return [void]
|
46
|
+
delegate [:fetch, :[], :key?, :keys, :values, :each, :has_key?] => :with_parent
|
17
47
|
|
18
48
|
# Returns a set of options used for the attributes. This isn't
|
19
49
|
# used at the moment.
|
@@ -27,10 +57,21 @@ module Mixture
|
|
27
57
|
# @return [Hash{Symbol => Array<Proc>}]
|
28
58
|
attr_reader :callbacks
|
29
59
|
|
60
|
+
# The parent of this attribute list. This is "merged" into this attribute
|
61
|
+
# list. This shouldn't be set since it is automatically assumed; however,
|
62
|
+
# sometimes it can be assumed wrong.
|
63
|
+
#
|
64
|
+
# @return [AttributeList, nil]
|
65
|
+
attr_accessor :parent
|
66
|
+
|
30
67
|
# Initializes the attribute list.
|
31
|
-
|
68
|
+
#
|
69
|
+
# @param parent [AttributeList] The parent {AttributeList}. This is used
|
70
|
+
# primarily for inheritance.
|
71
|
+
def initialize(parent = nil)
|
32
72
|
@list = {}
|
33
73
|
@options = {}
|
74
|
+
@parent = parent
|
34
75
|
@callbacks = Hash.new { |h, k| h[k] = Set.new }
|
35
76
|
end
|
36
77
|
|
@@ -42,5 +83,11 @@ module Mixture
|
|
42
83
|
def create(name, options = {})
|
43
84
|
@list[name] = Attribute.new(name, self, options)
|
44
85
|
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
def with_parent
|
90
|
+
@parent ? @list.merge(@parent.with_parent) : @list
|
91
|
+
end
|
45
92
|
end
|
46
93
|
end
|
data/lib/mixture/coerce/array.rb
CHANGED
data/lib/mixture/coerce/base.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "singleton"
|
4
5
|
|
@@ -101,12 +102,11 @@ module Mixture
|
|
101
102
|
# @yieldreturn (see .coerce_to)
|
102
103
|
# @return [void]
|
103
104
|
def self.data_block(data, &block)
|
104
|
-
|
105
|
-
when data.is_a?(::Symbol)
|
105
|
+
if data.is_a?(::Symbol)
|
106
106
|
proc { |value| value.public_send(data) }
|
107
|
-
|
107
|
+
elsif data.is_a?(::Proc)
|
108
108
|
data
|
109
|
-
|
109
|
+
elsif block_given?
|
110
110
|
block
|
111
111
|
else
|
112
112
|
fail ArgumentError, "Expected a block, got #{data.inspect}"
|
@@ -127,9 +127,11 @@ module Mixture
|
|
127
127
|
def to(type)
|
128
128
|
coercions = self.class.coercions
|
129
129
|
coercable = type.inheritable
|
130
|
-
|
131
|
-
|
132
|
-
"
|
130
|
+
.find { |ancestor| coercions.key?(ancestor) }
|
131
|
+
unless coercable
|
132
|
+
fail CoercionError, "Undefined coercion #{self.class.type} " \
|
133
|
+
"=> #{type}"
|
134
|
+
end
|
133
135
|
|
134
136
|
public_send(coercions[coercable])
|
135
137
|
end
|
data/lib/mixture/coerce/class.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Mixture
|
4
5
|
module Coerce
|
@@ -9,8 +10,10 @@ module Mixture
|
|
9
10
|
coerce_to(Types::Object, Itself)
|
10
11
|
coerce_to(Types::Class) do |value, type|
|
11
12
|
member = type.options.fetch(:members).first
|
12
|
-
|
13
|
-
|
13
|
+
unless value.is_a?(member)
|
14
|
+
fail CoercionError, "Cannot coerce #{value.class} =>" \
|
15
|
+
" #{member}"
|
16
|
+
end
|
14
17
|
value
|
15
18
|
end
|
16
19
|
end
|
data/lib/mixture/coerce/date.rb
CHANGED
data/lib/mixture/coerce/float.rb
CHANGED
data/lib/mixture/coerce/hash.rb
CHANGED
data/lib/mixture/coerce/nil.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Mixture
|
4
5
|
module Coerce
|
@@ -13,11 +14,8 @@ module Mixture
|
|
13
14
|
TryMethods = proc do |*methods|
|
14
15
|
proc do |value|
|
15
16
|
method = methods.find { |m| value.respond_to?(m) }
|
16
|
-
|
17
|
-
|
18
|
-
else
|
19
|
-
fail CoercionError, "Could not coerce #{value.class}"
|
20
|
-
end
|
17
|
+
fail CoercionError, "Could not coerce #{value.class}" unless method
|
18
|
+
value.public_send(method)
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
data/lib/mixture/coerce/range.rb
CHANGED
data/lib/mixture/coerce/set.rb
CHANGED
data/lib/mixture/coerce/time.rb
CHANGED
data/lib/mixture/coerce.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "mixture/coerce/base"
|
4
5
|
require "mixture/coerce/array"
|
@@ -65,13 +66,11 @@ module Mixture
|
|
65
66
|
begin
|
66
67
|
block.call(value, to)
|
67
68
|
rescue CoercionError
|
68
|
-
|
69
|
+
fail
|
69
70
|
rescue StandardError => e
|
70
|
-
|
71
|
+
fail CoercionError, "#{e.class}: #{e.message}", e.backtrace
|
71
72
|
end
|
72
73
|
end
|
73
|
-
|
74
|
-
# rubocop:disable Metrics/AbcSize
|
75
74
|
# rubocop:disable Metrics/MethodLength
|
76
75
|
|
77
76
|
# Registers the default coercions.
|
data/lib/mixture/errors.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Mixture
|
4
5
|
module Extensions
|
@@ -16,8 +17,10 @@ module Mixture
|
|
16
17
|
def attribute(name, options = {})
|
17
18
|
name = name.to_s.intern
|
18
19
|
attr = attributes.create(name, options)
|
19
|
-
define_method(attr.getter) { attribute(name) }
|
20
|
-
|
20
|
+
define_method(attr.getter) { attribute(name) } unless
|
21
|
+
options[:wo] || options[:write_only]
|
22
|
+
define_method(attr.setter) { |v| attribute(name, v) } unless
|
23
|
+
options[:ro] || options[:read_only]
|
21
24
|
attr
|
22
25
|
end
|
23
26
|
|
@@ -26,7 +29,12 @@ module Mixture
|
|
26
29
|
# @see AttributeList
|
27
30
|
# @return [AttributeList]
|
28
31
|
def attributes
|
29
|
-
@_attributes
|
32
|
+
return @_attributes if @_attributes
|
33
|
+
available = ancestors[1..-1]
|
34
|
+
.select { |c| c.respond_to?(:attributes) }
|
35
|
+
.first
|
36
|
+
parent = available ? available.attributes : nil
|
37
|
+
@_attributes = AttributeList.new(parent)
|
30
38
|
end
|
31
39
|
end
|
32
40
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "forwardable"
|
4
5
|
|
@@ -82,10 +83,9 @@ module Mixture
|
|
82
83
|
# @return [Object] The attribute's value, or the block's
|
83
84
|
# value instead.
|
84
85
|
def fetch(key, default = Undefined)
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
when default != Undefined then default
|
86
|
+
if key?(key.to_s.intern) then attribute(key.to_s.intern)
|
87
|
+
elsif block_given? then yield(key.to_s.intern)
|
88
|
+
elsif default != Undefined then default
|
89
89
|
else fail KeyError, "Undefined attribute #{key.to_s.intern}"
|
90
90
|
end
|
91
91
|
end
|
data/lib/mixture/extensions.rb
CHANGED
data/lib/mixture/model.rb
CHANGED
data/lib/mixture/types/access.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Mixture
|
4
5
|
module Types
|
@@ -21,7 +22,7 @@ module Mixture
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
+
private
|
25
26
|
|
26
27
|
# Actually creates the subtype. This should never be called
|
27
28
|
# outside of {.[]}. If `:noinfer` is set in the supertype's
|
data/lib/mixture/types/array.rb
CHANGED
data/lib/mixture/types/class.rb
CHANGED
data/lib/mixture/types/date.rb
CHANGED
data/lib/mixture/types/float.rb
CHANGED
data/lib/mixture/types/hash.rb
CHANGED
data/lib/mixture/types/nil.rb
CHANGED
data/lib/mixture/types/object.rb
CHANGED
data/lib/mixture/types/range.rb
CHANGED
data/lib/mixture/types/set.rb
CHANGED
data/lib/mixture/types/string.rb
CHANGED
data/lib/mixture/types/symbol.rb
CHANGED
data/lib/mixture/types/time.rb
CHANGED
data/lib/mixture/types/type.rb
CHANGED
data/lib/mixture/types.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Mixture
|
4
5
|
module Validate
|
@@ -16,8 +17,6 @@ module Mixture
|
|
16
17
|
super
|
17
18
|
error("Length is not acceptable") unless acceptable.cover?(length)
|
18
19
|
end
|
19
|
-
|
20
|
-
# rubocop:disable Metrics/AbcSize
|
21
20
|
# rubocop:disable Metrics/CyclomaticComplexity
|
22
21
|
# rubocop:disable Metrics/PerceivedComplexity
|
23
22
|
|
@@ -97,10 +96,9 @@ module Mixture
|
|
97
96
|
# @raise [ValidationError] If it cannot determine the length of
|
98
97
|
# the value.
|
99
98
|
def length
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
when @value.respond_to?(:count) then @value.count
|
99
|
+
if @value.respond_to?(:size) then @value.size
|
100
|
+
elsif @value.respond_to?(:length) then @value.length
|
101
|
+
elsif @value.respond_to?(:count) then @value.count
|
104
102
|
else error("Value isn't countable")
|
105
103
|
end
|
106
104
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Mixture
|
4
5
|
module Validate
|
@@ -16,7 +17,7 @@ module Mixture
|
|
16
17
|
error("Value does not match") unless match?
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
+
private
|
20
21
|
|
21
22
|
# Checks if the value matches the given matcher. It uses the
|
22
23
|
# `=~` operator. If it fails (i.e. raises an error), it returns
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Mixture
|
4
5
|
module Validate
|
@@ -15,7 +16,7 @@ module Mixture
|
|
15
16
|
error("Value is empty") if empty?
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
+
private
|
19
20
|
|
20
21
|
# Determins if the given value is empty. If it's not nil,
|
21
22
|
# and it responds to `empty?`, it returns the value of `empty?`;
|
data/lib/mixture/validate.rb
CHANGED
data/lib/mixture/version.rb
CHANGED
data/lib/mixture.rb
CHANGED
data/mixture.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
lib = File.expand_path("../lib", __FILE__)
|
4
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
@@ -16,10 +17,10 @@ Gem::Specification.new do |spec|
|
|
16
17
|
spec.license = "MIT"
|
17
18
|
|
18
19
|
spec.files = `git ls-files -z`.split("\x0")
|
19
|
-
|
20
|
+
.reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
21
|
spec.bindir = "bin"
|
21
22
|
spec.executables = spec.files
|
22
|
-
|
23
|
+
.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
24
|
spec.require_paths = ["lib"]
|
24
25
|
|
25
26
|
spec.add_development_dependency "bundler"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixture
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Rodi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -163,9 +163,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
163
163
|
version: '0'
|
164
164
|
requirements: []
|
165
165
|
rubyforge_project:
|
166
|
-
rubygems_version: 2.
|
166
|
+
rubygems_version: 2.5.2
|
167
167
|
signing_key:
|
168
168
|
specification_version: 4
|
169
169
|
summary: Handle validation, coercion, and attributes.
|
170
170
|
test_files: []
|
171
|
-
has_rdoc:
|