nrser 0.0.23 → 0.0.24

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bce188e694cb5fd687f3085a43602dc303a1c1ab
4
- data.tar.gz: affc25e12e51d899523c3a5fe5db6c498a997d8b
3
+ metadata.gz: ad84454dbdd85a4a86dbb940a0901cafe0effaef
4
+ data.tar.gz: 9992915527ce7f7749aac2d9bdf319a05507fd23
5
5
  SHA512:
6
- metadata.gz: 1946f2af31a5f40a84533d114d02513729308eb7ba06d3a2fd2f57ed1d4326718432a9aff3e64bb8be1e38703ffe1663bacc0ba0beeb67b68018472b2c8ab941
7
- data.tar.gz: '08ac5aff6d524538547eef3b00e07aa916301b83bb6812980af20d341c714a25dfcd0d1a8957cf939fd112becdac7b3182507c20c97913d56b08888d7639d60e'
6
+ metadata.gz: 995db23a4d353e6a54fec4480e3d17175b99efb75a0a08cc0583a3b166fa1153a26ce58b66d2b592306a17d495ca3544a805a06a03fb06516337f072ee22eb91
7
+ data.tar.gz: 47488b4ca3a7655f5264578a6e9283b04e2e1148093c72ec032cbc03720f098d6e7531cd44ccc1e20f9ec3e4ea063a905fb4f4699b6793042a816e0a7f5d6ca7
@@ -115,7 +115,7 @@ module NRSER
115
115
  key = block.call element
116
116
 
117
117
  if result.key? key
118
- raise NRSER::ConflictError.dedented <<-END
118
+ raise NRSER::ConflictError.new NRSER.dedent <<-END
119
119
  Key #{ key.inspect } is already in results with value:
120
120
 
121
121
  #{ result[key].pretty_inspect }
@@ -13,5 +13,33 @@ module NRSER
13
13
  NRSER.rest self
14
14
  end # #rest
15
15
 
16
+
17
+ # Returns a lambda that calls accepts a single arg and calls `#dig` on it
18
+ # with the elements of *this* array as arguments.
19
+ #
20
+ # @example
21
+ # list = [{id: 1, name: "Neil"}, {id: 2, name: "Mica"}]
22
+ # list.to_h_by &[:id].digger
23
+ # # => {
24
+ # # 1 => {id: 1, name: "Neil"},
25
+ # # 2 => {id: 2, name: "Mica"},
26
+ # # }
27
+ #
28
+ # @todo
29
+ # I wanted to use `#to_proc` so that you could use `&[:id]`, but unary
30
+ # `&` doesn't invoke refinements, and I don't really want to monkey-patch
31
+ # anything, especially something as core as `#to_proc` and `Array`.
32
+ #
33
+ # @return [Proc]
34
+ # Lambda proc that accepts a single argument and calls `#dig` with this
35
+ # array's contents as the `#dig` arguments.
36
+ #
37
+ def digger
38
+ ->(digable) {
39
+ digable.dig *self
40
+ }
41
+ end # #digable
42
+
43
+
16
44
  end # refine ::Array
17
45
  end # NRSER
@@ -21,7 +21,7 @@ module NRSER::Types
21
21
  end # IsA
22
22
 
23
23
  # class membership
24
- def self.is_a klass
25
- IsA.new klass
24
+ def self.is_a klass, **options
25
+ IsA.new klass, **options
26
26
  end
27
27
  end # NRSER::Types
@@ -0,0 +1,83 @@
1
+ # Requirements
2
+ # =======================================================================
3
+
4
+ # stdlib
5
+ require 'pathname'
6
+
7
+ # gems
8
+
9
+ # package
10
+ require_relative './is_a'
11
+ require_relative './where'
12
+ require_relative './combinators'
13
+
14
+
15
+ # Refinements
16
+ # =======================================================================
17
+
18
+ require 'nrser/refinements'
19
+ using NRSER
20
+
21
+
22
+ # Declarations
23
+ # =======================================================================
24
+
25
+ module NRSER; end
26
+
27
+
28
+ # Definitions
29
+ # =======================================================================
30
+
31
+ module NRSER::Types
32
+
33
+ # A {Pathname} type that provides a `from_s`
34
+ PATHNAME = is_a \
35
+ Pathname,
36
+ name: 'PathnameType',
37
+ from_s: ->(string) { Pathname.new string }
38
+
39
+
40
+ # A type satisfied by a {Pathname} instance that's not empty (meaning it's
41
+ # string representation is not empty).
42
+ NON_EMPTY_PATHNAME = intersection \
43
+ PATHNAME,
44
+ where { |value| value.to_s.length > 0 },
45
+ name: 'NonEmptyPathnameType'
46
+
47
+
48
+ PATH = union non_empty_str, NON_EMPTY_PATHNAME, name: 'Path'
49
+
50
+
51
+ # Eigenclass (Singleton Class)
52
+ # ========================================================================
53
+ #
54
+ class << self
55
+
56
+ def pathname **options
57
+ if options.empty?
58
+ PATHNAME
59
+ else
60
+ is_a \
61
+ Pathname,
62
+ name: 'PathnameType',
63
+ from_s: ->(string) { Pathname.new string },
64
+ **options
65
+ end
66
+ end
67
+
68
+ #
69
+ #
70
+ # @return [NRSER::Types::Type]
71
+ #
72
+ def path **options
73
+ if options.empty?
74
+ PATH
75
+ else
76
+ union non_empty_str, NON_EMPTY_PATHNAME, **options
77
+ end
78
+ end # #path
79
+
80
+ end # class << self (Eigenclass)
81
+
82
+ end # module NRSER::Types
83
+
@@ -7,10 +7,29 @@ module NRSER::Types
7
7
  name.split('::').last
8
8
  end
9
9
 
10
- def initialize **options
11
- @name = options[:name]
12
- @from_s = options[:from_s]
13
- end
10
+
11
+ # Constructor
12
+ # =====================================================================
13
+
14
+ # Instantiate a new `NRSER::Types::Type`.
15
+ #
16
+ # @param [nil | String] name:
17
+ # Name that will be used when displaying the type, or `nil` to use a
18
+ # default generated name.
19
+ #
20
+ # @param [nil | #call] from_s:
21
+ # Callable that will be passed a {String} and should return an object
22
+ # that satisfies the type if it possible to create one.
23
+ #
24
+ # The returned value *will* be checked against the type, so returning a
25
+ # value that doesn't satisfy will result in a {TypeError} being raised
26
+ # by {#from_s}.
27
+ #
28
+ def initialize name: nil, from_s: nil
29
+ @name = name
30
+ @from_s = from_s
31
+ end # #initialize
32
+
14
33
 
15
34
  def name
16
35
  @name || default_name
@@ -52,7 +71,7 @@ module NRSER::Types
52
71
  raise NoMethodError, "#from_s not defined"
53
72
  end
54
73
 
55
- check @from_s.(s)
74
+ check @from_s.call( s )
56
75
  end
57
76
 
58
77
  def has_from_s?
data/lib/nrser/types.rb CHANGED
@@ -1,19 +1,68 @@
1
+ # Requirements
2
+ # =======================================================================
3
+
4
+ # Stdlib
5
+ # ---------------------------------------------------------------------
6
+
7
+ # TODO Not sure if this needs to be here... can't find any usage of it in
8
+ # quick searches, but I don't want to remove it now.
1
9
  require 'pp'
2
10
 
3
- require 'nrser/refinements'
4
- require 'nrser/types/type'
5
- require 'nrser/types/is'
6
- require 'nrser/types/is_a'
7
- require 'nrser/types/where'
8
- require 'nrser/types/combinators'
9
- require 'nrser/types/maybe'
10
- require 'nrser/types/attrs'
11
- require 'nrser/types/responds'
11
+ # Deps
12
+ # ---------------------------------------------------------------------
13
+
14
+ # Package
15
+ # ---------------------------------------------------------------------
16
+
17
+ # Abstract infrastructure for type creation - stuff that doesn't define any
18
+ # concrete type instances.
19
+ #
20
+ # Files that define concrete type instances on load (usually as module
21
+ # constants, which I'm still questioning a bit as a design because of the
22
+ # uncontrollable mutability of Ruby and the importance of type checks)
23
+ # need to be required in the "Post-Processing" section at the bottom.
24
+ #
25
+ require_relative './types/type'
26
+ require_relative './types/is'
27
+ require_relative './types/is_a'
28
+ require_relative './types/where'
29
+ require_relative './types/combinators'
30
+ require_relative './types/maybe'
31
+ require_relative './types/attrs'
32
+ require_relative './types/responds'
33
+
12
34
 
35
+ # Refinements
36
+ # =======================================================================
37
+
38
+ require 'nrser/refinements'
13
39
  using NRSER
14
-
40
+
41
+
42
+ # Stuff to help you define, test, check and match types in Ruby.
43
+ #
15
44
  module NRSER::Types
16
- # make a type.
45
+
46
+ # Make a {NRSER::Types::Type} from a value.
47
+ #
48
+ # If the `value` argument is...
49
+ #
50
+ # - a {NRSER::Types::Type}, it is returned.
51
+ #
52
+ # - a {Class}, a new {NRSER::Types::IsA} matching that class is returned.
53
+ #
54
+ # This allows things like
55
+ #
56
+ # NRSER::Types.check 's', String
57
+ # NRSER::Types.match 's', String, ->(s) { ... }
58
+ #
59
+ # - anything else, a new {NRSER::Types::Is} matching that value is
60
+ # returned.
61
+ #
62
+ # @param [Object] value
63
+ #
64
+ # @return [NRSER::Types::Type]
65
+ #
17
66
  def self.make value
18
67
  if value.is_a? NRSER::Types::Type
19
68
  value
@@ -24,15 +73,18 @@ module NRSER::Types
24
73
  end
25
74
  end
26
75
 
76
+
27
77
  # raise an error if value doesn't match type.
28
78
  def self.check value, type
29
79
  make(type).check value
30
80
  end
31
81
 
82
+
32
83
  def self.test value, type
33
84
  make(type).test value
34
85
  end
35
86
 
87
+
36
88
  def self.match value, *clauses
37
89
  if clauses.empty?
38
90
  raise ArgumentError.new NRSER.dedent <<-END
@@ -84,7 +136,8 @@ module NRSER::Types
84
136
  #{ enum.map {|type, expression| "\n #{ type.inspect }"} }
85
137
 
86
138
  END
87
- end
139
+ end # .match
140
+
88
141
 
89
142
  # make a type instance from a object representation that can come from
90
143
  # a YAML or JSON declaration.
@@ -98,15 +151,22 @@ module NRSER::Types
98
151
 
99
152
  },
100
153
  }
101
- end
154
+ end # .from_repr
155
+
102
156
  end # NRSER::Types
103
157
 
104
- # things that define values, which may need to call the functions defined
105
- # above
106
- require 'nrser/types/any'
107
- require 'nrser/types/booleans'
108
- require 'nrser/types/numbers'
109
- require 'nrser/types/strings'
110
- require 'nrser/types/symbol'
111
- require 'nrser/types/array'
112
- require 'nrser/types/hash'
158
+
159
+ # Post-Processing
160
+ # =======================================================================
161
+ #
162
+ # Files that define constants that need the proceeding infrastructure.
163
+ #
164
+
165
+ require_relative './types/any'
166
+ require_relative './types/booleans'
167
+ require_relative './types/numbers'
168
+ require_relative './types/strings'
169
+ require_relative './types/symbol'
170
+ require_relative './types/array'
171
+ require_relative './types/hash'
172
+ require_relative './types/paths'
data/lib/nrser/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module NRSER
2
- VERSION = "0.0.23"
2
+ VERSION = "0.0.24"
3
3
 
4
4
  module Version
5
5
 
@@ -93,5 +93,19 @@ describe "NRSER Enumerable Methods" do
93
93
  end # NRSER.method(:find_only)
94
94
 
95
95
 
96
+ describe NRSER.method(:to_h_by) do
97
+
98
+ context "Duplicate keys" do
99
+ it "raises NRSER::ConflictError" do
100
+ expect {
101
+ NRSER.to_h_by([1, 2, 3]) { |i| i % 2 }
102
+ }.to raise_error NRSER::ConflictError
103
+ end
104
+ end # Duplicate keys
105
+
106
+
107
+ end # NRSER.to_h_by
108
+
109
+
96
110
  end # NRSER Enumerable Methods
97
111
 
@@ -149,6 +149,28 @@ describe NRSER::Types do
149
149
  fail: [ [] ],
150
150
  },
151
151
 
152
+ t.path => {
153
+ pass: [
154
+ '.',
155
+ Pathname.getwd,
156
+ ],
157
+
158
+ fail: [
159
+ '',
160
+ 123,
161
+ ],
162
+
163
+ from_s: {
164
+ pass: [
165
+ '.',
166
+ ],
167
+
168
+ fail: [
169
+ '',
170
+ ],
171
+ },
172
+ }, # t.path
173
+
152
174
  }.each do |type, tests|
153
175
  if tests[:pass]
154
176
  tests[:pass].each do |value|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nrser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.23
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - nrser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-17 00:00:00.000000000 Z
11
+ date: 2017-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -174,6 +174,7 @@ files:
174
174
  - lib/nrser/types/is_a.rb
175
175
  - lib/nrser/types/maybe.rb
176
176
  - lib/nrser/types/numbers.rb
177
+ - lib/nrser/types/paths.rb
177
178
  - lib/nrser/types/responds.rb
178
179
  - lib/nrser/types/strings.rb
179
180
  - lib/nrser/types/symbol.rb