striuct 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c59316edafe027980857f258404996caaee0be26a0ad3265acee3cb067477db6
4
- data.tar.gz: '086afe2f12bb06050cd7964a774fd087e6a7a710f0d54fe6bb3c4e647490e2d7'
3
+ metadata.gz: d820670e757190ed2db502b8d6e0c53a7689f299262695f3ca18cec69dd5270b
4
+ data.tar.gz: 8a27cca712c9a63c2a5207090a6a8d0d8dcecd24a13bf07fa16c243a3b24c366
5
5
  SHA512:
6
- metadata.gz: 86c436676285e90dbafd4e1f9293b5cccfda99ce060e07a38893f4f0979c4c9f0b7c1c41da63e10ee479ff1323fa0f585c92113929bce766b072e577dc95b8cb
7
- data.tar.gz: 0fca1e67d31013254edeb00043cf42699a3845b83bd4979db8623d0ef2786daff07db0ced0dcda068f297e1d577fca063703592f65242c26d793a3e17e9fb786
6
+ metadata.gz: c90d1e6cc1ac20015660134d88d863dc935d6db44128e0f49f7c807b6b357d4821055d989e9e9e3a8bb4c49382acbab04509bf0445389a454c72c3fb729cbd85
7
+ data.tar.gz: a7154a914174099a8b5d32fe4b534811c14187f3fb9e8735cba701764b7d9aee640de1c276711dcedb85915f33efc9fecac87dde0ae8a09d704d0bbf84f3f11b
data/README.md CHANGED
@@ -1,49 +1,29 @@
1
- striuct
2
- =======
1
+ # striuct
3
2
 
4
3
  ![Build Status](https://github.com/kachick/striuct/actions/workflows/test_behaviors.yml/badge.svg?branch=main)
5
4
  [![Gem Version](https://badge.fury.io/rb/striuct.png)](http://badge.fury.io/rb/striuct)
6
5
 
7
- Description
8
- -----------
9
-
10
6
  Struct++
11
7
 
12
- Features
13
- --------
14
-
15
- ### Strict
16
-
17
- * Easy and Flexible Validations
18
- * Prevent to conflict member names
19
- * Lock setters for each member
20
-
21
- ### Useful
22
-
23
- * Hook just before setters
24
- * Default value
25
- * Member aliasing
26
- * Inheritable
27
- * Handling between nil <-> unassigned
28
- * Similar API for Hash
29
-
30
- ### Onepoint
31
-
32
- * Base API looks like Struct
33
- * Pure Ruby :)
34
-
35
- Usage
36
- -----
8
+ ## Usage
37
9
 
38
10
  Require Ruby 2.6 or later
39
11
 
40
12
  Add this line to your `Gemfile`
41
13
 
42
14
  ```ruby
43
- gem 'striuct', '>= 0.7.0', '< 0.8.0'
15
+ gem 'striuct', '>= 0.8.0', '< 0.9.0'
44
16
  ```
45
17
 
46
- ### Overview - Case 1
18
+ Then add below code into your Ruby code
19
+
20
+ ```ruby
21
+ require 'striuct'
22
+ ```
23
+
24
+ ### Overview
25
+
26
+ #### Case 1
47
27
 
48
28
  ```ruby
49
29
  require 'striuct'
@@ -72,7 +52,7 @@ ken = User[name: 'ken'] # Construct from hash
72
52
  ken.id #=> 2
73
53
  ```
74
54
 
75
- ### Overview - Case 2
55
+ #### Case 2
76
56
 
77
57
  ```ruby
78
58
  class Foo < Striuct
@@ -102,7 +82,7 @@ foo.with_adjuster = '5'
102
82
  foo.with_adjuster #=> 5 # Casted via adjuster
103
83
  ```
104
84
 
105
- ### Overview - Case 3
85
+ #### Case 3
106
86
 
107
87
  ```ruby
108
88
  class UseMustOption < Striuct
@@ -112,8 +92,32 @@ end
112
92
  UseMustOption.new #=> InvalidOperationError "`foo` require a value under `must` option "
113
93
  ```
114
94
 
115
- Link
116
- ----
95
+ ## Features
96
+
97
+ ### Strict
98
+
99
+ * Easy and Flexible Validations
100
+ * Basically use `#===` for the validation
101
+ * The pattern builder DSL is just using [eqq](https://github.com/kachick/eqq)
102
+ * When passed the Proc, it will be evaluated in the instance context
103
+ * Prevent to conflict member names
104
+ * Lock setters for each member
105
+
106
+ ### Useful
107
+
108
+ * Hook just before setters
109
+ * Default value
110
+ * Member aliasing
111
+ * Inheritable
112
+ * Handling between nil <-> unassigned
113
+ * Similar API for Hash
114
+
115
+ ### Finally
116
+
117
+ * Base API looks like Struct
118
+ * Pure Ruby :)
119
+
120
+ ## Link
117
121
 
118
122
  * [Repository](https://github.com/kachick/striuct)
119
123
  * [API documents](https://kachick.github.io/striuct/)
data/lib/striuct.rb CHANGED
@@ -7,6 +7,10 @@
7
7
  class Striuct
8
8
  class Error < StandardError; end
9
9
  class InvalidOperationError < Error; end
10
+ class InvalidValueError < Error; end
11
+ class InvalidWritingError < InvalidValueError; end
12
+ class InvalidReadingError < InvalidValueError; end
13
+ class InvalidAdjustingError < InvalidValueError; end
10
14
  end
11
15
 
12
- require_relative 'striuct/requirements'
16
+ require_relative 'striuct/bootstrap'
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'validation'
3
+ require 'forwardable'
4
+ require 'eqq'
5
+
4
6
  require_relative 'structs'
5
7
  require_relative 'classmethods/requirements'
6
8
  require_relative 'instancemethods/requirements'
@@ -4,6 +4,68 @@ class Striuct
4
4
  module ClassMethods
5
5
  # @group Adjuster
6
6
 
7
+ # Adjuster Builders
8
+ # Apply adjuster when passed pattern.
9
+ # @param pattern [Proc, Method, #===]
10
+ # @param adjuster [Proc, #to_proc]
11
+ # @return [Proc]
12
+ def WHEN(pattern, adjuster)
13
+ unless Eqq.valid?(pattern)
14
+ raise ArgumentError, 'wrong object for pattern'
15
+ end
16
+
17
+ unless Striuct.adjustable?(adjuster)
18
+ raise ArgumentError, 'wrong object for adjuster'
19
+ end
20
+
21
+ ->v { _valid?(pattern, v) ? adjuster.call(v) : v }
22
+ end
23
+
24
+ # Sequential apply all adjusters.
25
+ # @param adjuster1 [Proc, #to_proc]
26
+ # @param adjuster2 [Proc, #to_proc]
27
+ # @param adjusters [Proc, #to_proc]
28
+ # @return [Proc]
29
+ def INJECT(adjuster1, adjuster2, *adjusters)
30
+ adjusters = [adjuster1, adjuster2, *adjusters]
31
+
32
+ unless adjusters.all? { |f| adjustable?(f) }
33
+ raise ArgumentError, 'wrong object for adjuster'
34
+ end
35
+
36
+ ->v {
37
+ adjusters.reduce(v) { |ret, adjuster| adjuster.call(ret) }
38
+ }
39
+ end
40
+
41
+ # Accept any parser when that respond to parse method.
42
+ # @param parser [#parse]
43
+ # @return [Proc]
44
+ def PARSE(parser)
45
+ if !::Integer.equal?(parser) && !parser.respond_to?(:parse)
46
+ raise ArgumentError, 'wrong object for parser'
47
+ end
48
+
49
+ ->v {
50
+ if ::Integer.equal?(parser)
51
+ ::Kernel.Integer(v)
52
+ else
53
+ parser.parse(
54
+ case v
55
+ when String
56
+ v
57
+ when ->_ { v.respond_to?(:to_str) }
58
+ v.to_str
59
+ when ->_ { v.respond_to?(:read) }
60
+ v.read
61
+ else
62
+ raise TypeError, 'wrong object for parsing source'
63
+ end
64
+ )
65
+ end
66
+ }
67
+ end
68
+
7
69
  # @param [Symbol, String, #to_sym, Integer, #to_int] key - name / index
8
70
  def adjuster_for(key)
9
71
  autonym = autonym_for_key(key)
@@ -32,7 +32,7 @@ class Striuct
32
32
  end
33
33
 
34
34
  def condition=(condition)
35
- unless ::Validation.conditionable?(condition)
35
+ unless Eqq.valid?(condition)
36
36
  raise TypeError, 'wrong object for condition'
37
37
  end
38
38
 
@@ -40,7 +40,7 @@ class Striuct
40
40
  end
41
41
 
42
42
  def adjuster=(adjuster)
43
- unless ::Validation.adjustable?(adjuster)
43
+ unless Striuct.adjustable?(adjuster)
44
44
  raise ArgumentError, 'wrong object for adjuster'
45
45
  end
46
46
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'keyvalidatable'
4
-
5
3
  class Striuct
6
4
  module ClassMethods
7
5
  # @group Constructor
@@ -16,9 +14,8 @@ class Striuct
16
14
  # @param [Hash, Struct, Striuct, #each_pair] pairs
17
15
  # @return [Striuct]
18
16
  def for_pairs(pairs)
19
- raise TypeError, 'no pairs object' unless pairs.respond_to?(:each_pair)
20
-
21
- KeyValidatable.validate_array(KeyValidatable.keys_for(pairs).map(&:to_sym), let: all_members)
17
+ raise ArgumentError, 'no pairs object' unless pairs.respond_to?(:each_pair)
18
+ raise ArgumentError unless pairs.each_pair { |key, _value| all_members.include?(key.to_sym) }
22
19
 
23
20
  instance = allocate
24
21
  instance.__send__(:initialize_for_pairs, pairs)
@@ -46,7 +43,7 @@ class Striuct
46
43
 
47
44
  invalids = autonyms.select { |autonym| !instance.valid?(autonym) }
48
45
  if strict && !invalids.empty?
49
- raise Validation::InvalidWritingError,
46
+ raise InvalidWritingError,
50
47
  "invalids members are, yet '#{invalids.inspect} in #{self}'"
51
48
  end
52
49
 
@@ -4,36 +4,25 @@ class Striuct
4
4
  module ClassMethods
5
5
  # @group Macro for Member Definition
6
6
 
7
- ANYTHING = ::Validation::Condition.anything
7
+ ANYTHING = Eqq.ANYTHING()
8
8
 
9
9
  # @return [Class]
10
- ADD_MEMBER_OptArg = OptionalArgument.define {
11
- opt(:default_value, aliases: [:default])
12
- opt(:default_proc, aliases: [:lazy_default])
13
- conflict(:default_value, :default_proc)
14
- opt(:must, default: false)
15
- opt(:setter_validation, aliases: [:writer_validation], default: true)
16
- opt(:getter_validation, aliases: [:reader_validation], default: false)
17
- }
18
10
 
19
11
  private
20
12
 
21
13
  # @param [Symbol, String, #to_sym] autonym
22
- # @param [#===, Proc, Method] condition
23
- # @param [Hash] options
24
- # @option options [BasicObject] :default
25
- # @option options [Proc] :default_proc
26
- # @option options [Boolean] :must
27
- # @option options [Boolean] :reader_validation
28
- # @option options [Boolean] :getter_validation
29
- # @option options [Boolean] :writer_validation
30
- # @option options [Boolean] :setter_validation
31
- # @return [nil]
32
- def add_member(autonym, condition=anything, options={}, &adjuster)
14
+ # @param [#===, Proc, Method] pattern
15
+ # @param [Proc] default_proc
16
+ # @param [Boolean] must
17
+ # @param [Boolean] writer_validation
18
+ # @param [Boolean] reader_validation
19
+ # @return [void]
20
+ def add_member(autonym, pattern=ANYTHING, default_value: nil, default_proc: nil, must: false, writer_validation: true, reader_validation: false, &adjuster)
33
21
  _check_frozen
34
22
  _check_closed
35
23
 
36
- options = ADD_MEMBER_OptArg.parse(options)
24
+ raise ArgumentError if !default_value.nil? && default_proc
25
+
37
26
  autonym = autonym.to_sym # First definition for an autonym
38
27
 
39
28
  raise ArgumentError, %Q!already exist name "#{autonym}"! if member?(autonym)
@@ -41,21 +30,21 @@ class Striuct
41
30
  _check_safety_naming(autonym)
42
31
  _add_autonym(autonym)
43
32
 
44
- _attributes_for(autonym).safety_setter = !!options.setter_validation
45
- _attributes_for(autonym).safety_getter = !!options.getter_validation
33
+ _attributes_for(autonym).safety_setter = writer_validation
34
+ _attributes_for(autonym).safety_getter = reader_validation
46
35
 
47
- if options.must
36
+ if must
48
37
  _attributes_for(autonym).must = true
49
38
  end
50
39
 
51
40
  _def_getter(autonym)
52
- _def_setter(autonym, condition, &adjuster)
41
+ _def_setter(autonym, pattern, &adjuster)
53
42
 
54
43
  case
55
- when options.default_value?
56
- set_default_value(autonym, options.default_value)
57
- when options.default_proc?
58
- set_default_value(autonym, &options.default_proc)
44
+ when !default_value.nil?
45
+ set_default_value(autonym, default_value)
46
+ when default_proc
47
+ set_default_value(autonym, &default_proc)
59
48
  end
60
49
 
61
50
  nil
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'optionalargument'
4
-
5
3
  require_relative 'hashdeepdupulicatable'
6
4
  require_relative 'attributes'
7
5
  require_relative 'inner'
@@ -37,7 +37,7 @@ class Striuct
37
37
  value = @db[autonym]
38
38
 
39
39
  if with_safety_getter?(autonym) && !accept?(autonym, value)
40
- raise ::Validation::InvalidReadingError,
40
+ raise InvalidReadingError,
41
41
  "#{value.inspect} is deficient for #{autonym} in #{self.class}"
42
42
  end
43
43
 
@@ -1,21 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
4
- require 'keyvalidatable'
5
-
6
3
  class Striuct
7
4
  module InstanceMethods
8
5
  extend Forwardable
9
6
 
10
7
  # hide Forwardable's public/protected class_macro
11
8
  private_class_method(*Forwardable.instance_methods)
12
-
13
- include KeyValidatable
14
9
  end
15
10
  end
16
11
 
17
12
  require_relative 'delegate_class_methods'
18
- require_relative 'keyvalidatable'
19
13
  require_relative 'object'
20
14
  require_relative 'compare'
21
15
  require_relative 'to_s'
@@ -9,7 +9,7 @@ class Striuct
9
9
  def []=(key, value)
10
10
  autonym = autonym_for_key(key)
11
11
  _set(autonym, value)
12
- rescue Validation::InvalidWritingError
12
+ rescue InvalidWritingError
13
13
  $!.set_backtrace(
14
14
  ["#{$!.backtrace[-1].sub(/[^:]+\z/) { '' }}in `[#{key.inspect}(#{autonym})]=': #{$!.message}", $!.backtrace[-1]]
15
15
  )
@@ -31,17 +31,17 @@ class Striuct
31
31
  begin
32
32
  value = instance_exec(value, &adjuster_for(autonym))
33
33
  rescue Exception
34
- raise ::Validation::InvalidAdjustingError
34
+ raise InvalidAdjustingError
35
35
  end
36
36
  end
37
37
 
38
38
  if with_safety_setter?(autonym) && !accept?(autonym, value)
39
- raise ::Validation::InvalidWritingError,
39
+ raise InvalidWritingError,
40
40
  "#{value.inspect} is deficient for #{autonym} in #{self.class}"
41
41
  end
42
42
 
43
43
  @db[autonym] = value
44
- rescue ::Validation::InvalidError
44
+ rescue InvalidValueError
45
45
  unless /in \[\]=/.match?(caller(2..2).first.slice(/([^:]+)\z/))
46
46
  $!.backtrace.delete_if { |s| /#{Regexp.escape(File.dirname(__FILE__))}/ =~ s }
47
47
  $!.backtrace.first.sub!(/([^:]+)\z/) { "in `#{autonym}='" }
@@ -4,6 +4,21 @@ class Striuct
4
4
  module InstanceMethods
5
5
  # @group Validation
6
6
 
7
+ # @param [Proc, Method, #===] pattern
8
+ # @param [Object] value
9
+ def _valid?(pattern, value)
10
+ !!(
11
+ case pattern
12
+ when Proc
13
+ instance_exec(value, &pattern)
14
+ when Method
15
+ pattern.call(value)
16
+ else
17
+ pattern === value
18
+ end
19
+ )
20
+ end
21
+
7
22
  # @param [Symbol, String, #to_sym, Integer, #to_int] key - name / index
8
23
  # @param value
9
24
  # true if passed under any condition
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'validation'
4
-
5
3
  class Striuct
6
4
  class << self
7
5
  alias_method :new_instance, :new
@@ -40,6 +38,20 @@ class Striuct
40
38
  }
41
39
  end
42
40
 
41
+ # Return `true` if given object is sufficient as an adjuster role
42
+ def adjustable?(object)
43
+ case object
44
+ when Proc
45
+ object.arity == 1
46
+ else
47
+ if object.respond_to?(:to_proc)
48
+ object.to_proc.arity == 1
49
+ else
50
+ false
51
+ end
52
+ end
53
+ end
54
+
43
55
  private
44
56
 
45
57
  def inherited(subclass)
@@ -48,7 +60,7 @@ class Striuct
48
60
  subclass.class_eval {
49
61
  extend ClassMethods
50
62
  include Enumerable
51
- include Validation
63
+ extend Eqq::Buildable
52
64
  include InstanceMethods
53
65
 
54
66
  _init
metadata CHANGED
@@ -1,75 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: striuct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenichi Kamiya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-03 00:00:00.000000000 Z
11
+ date: 2021-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: validation
14
+ name: eqq
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.2.2
19
+ version: 0.0.5
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 0.3.0
22
+ version: 0.1.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 0.2.2
29
+ version: 0.0.5
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.3.0
33
- - !ruby/object:Gem::Dependency
34
- name: optionalargument
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: 0.5.1
40
- - - "<"
41
- - !ruby/object:Gem::Version
42
- version: 0.6.0
43
- type: :runtime
44
- prerelease: false
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 0.5.1
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: 0.6.0
53
- - !ruby/object:Gem::Dependency
54
- name: keyvalidatable
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - ">="
58
- - !ruby/object:Gem::Version
59
- version: 0.2.0
60
- - - "<"
61
- - !ruby/object:Gem::Version
62
- version: 0.3.0
63
- type: :runtime
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: 0.2.0
70
- - - "<"
71
- - !ruby/object:Gem::Version
72
- version: 0.3.0
32
+ version: 0.1.0
73
33
  description: " Struct + validation + inheritable + default_value + etc...\n"
74
34
  email:
75
35
  - kachick1+ruby@gmail.com
@@ -80,6 +40,7 @@ files:
80
40
  - MIT-LICENSE.txt
81
41
  - README.md
82
42
  - lib/striuct.rb
43
+ - lib/striuct/bootstrap.rb
83
44
  - lib/striuct/classmethods/README.md
84
45
  - lib/striuct/classmethods/adjustment.rb
85
46
  - lib/striuct/classmethods/attributes.rb
@@ -107,7 +68,6 @@ files:
107
68
  - lib/striuct/instancemethods/enum.rb
108
69
  - lib/striuct/instancemethods/getter.rb
109
70
  - lib/striuct/instancemethods/hashy.rb
110
- - lib/striuct/instancemethods/keyvalidatable.rb
111
71
  - lib/striuct/instancemethods/lock.rb
112
72
  - lib/striuct/instancemethods/object.rb
113
73
  - lib/striuct/instancemethods/requirements.rb
@@ -116,7 +76,6 @@ files:
116
76
  - lib/striuct/instancemethods/to_s.rb
117
77
  - lib/striuct/instancemethods/validation.rb
118
78
  - lib/striuct/instancemethods/values.rb
119
- - lib/striuct/requirements.rb
120
79
  - lib/striuct/singleton_class.rb
121
80
  - lib/striuct/structs.rb
122
81
  homepage: https://github.com/kachick/striuct
@@ -142,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
101
  - !ruby/object:Gem::Version
143
102
  version: '0'
144
103
  requirements: []
145
- rubygems_version: 3.1.4
104
+ rubygems_version: 3.2.15
146
105
  signing_key:
147
106
  specification_version: 4
148
107
  summary: Struct++
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Striuct
4
- module InstanceMethods
5
- KeyValidatable.instance_methods.each do |feature|
6
- if specific_feature = feature.to_s.sub!('members') { 'autonyms' }
7
- def_delegator :self, feature, specific_feature.to_sym
8
- end
9
- end
10
- end
11
- end