mixture 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|