nrser 0.0.15 → 0.0.16

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: 87e8fd49793cd5ab294a3228fef5d7745aac398b
4
- data.tar.gz: e6caa34bb3336e50e689d1142680ed7796e512f7
3
+ metadata.gz: 4bdcf46a3991ba3ea386aa2599d03dd3f9bbbfff
4
+ data.tar.gz: d59e2df7bcead37764dbe4d167eeed44f2e0e22f
5
5
  SHA512:
6
- metadata.gz: c81efda7e8c7d3a01cd2dc5220225ea6cb7edd8d043aaccb3cbd03bfaa23bf4ffb7566cce9dbde92869c3a230f7561b95d9f4c1760933b45a8731abaefd3ef6b
7
- data.tar.gz: 7380a8705ee19f7cb6d8b5d602b6a852c7b2b6c84a47b0ba8bdd20999e6720c4cb2551d3d26ad0bf346e3da04ca16beb80d437b319dc80ff496221ac31136f7b
6
+ metadata.gz: 1c4985fc5450eaa3c2989b813b83d477e28b3a07dedecb2c0158ca182f484a9106edfe26d56957188829d642dba614ad75510851125be124732b280ebb0ba66e
7
+ data.tar.gz: 4898d4bd6023429747b7e657fbecb9dc614daa1ba7a7dfe39c419b36f9714c75ce44d18a4f6144e51f02592b6e11d6bb20619d916b3b684a22b7c1a86addecf1
data/.gitignore CHANGED
@@ -21,3 +21,14 @@ tmp
21
21
  *.a
22
22
  mkmf.log
23
23
  tmp/
24
+ ##############################################################################
25
+ # BEGIN Qb.gitingore
26
+ #
27
+ # generated qb playbooks
28
+ .qb-playbook.yml
29
+
30
+ # ansible retry files
31
+ .qb-playbook.retry
32
+ #
33
+ # END Qb.gitingore
34
+ ##############################################################################
data/lib/nrser.rb CHANGED
@@ -114,3 +114,5 @@ module NRSER
114
114
 
115
115
  end # class << self
116
116
  end
117
+
118
+ require "nrser/types"
@@ -1,3 +1,5 @@
1
+ require 'pathname'
2
+
1
3
  module NRSER
2
4
  refine Object do
3
5
  def pipe
@@ -38,4 +40,38 @@ module NRSER
38
40
  NRSER.template self, str
39
41
  end
40
42
  end
43
+
44
+ refine Pathname do
45
+ # override to accept Pathname instances.
46
+ #
47
+ # @param [String] *prefixes
48
+ # the prefixes to see if the Pathname starts with.
49
+ #
50
+ # @return [Boolean]
51
+ # true if the Pathname starts with any of the prefixes.
52
+ #
53
+ def start_with? *prefixes
54
+ to_s.start_with? *prefixes.map(&:to_s)
55
+ end
56
+
57
+ # override sub to support Pathname instances as patterns.
58
+ #
59
+ # @param [String | Regexp | Pathname] pattern
60
+ # thing to replace.
61
+ #
62
+ # @param [String | Hash] replacement
63
+ # thing to replace it with.
64
+ #
65
+ # @return [Pathname]
66
+ # new Pathname.
67
+ #
68
+ def sub pattern, replacement
69
+ case pattern
70
+ when Pathname
71
+ super pattern.to_s, replacement
72
+ else
73
+ super pattern, replacement
74
+ end
75
+ end
76
+ end # Pathname
41
77
  end # NRSER
@@ -0,0 +1,75 @@
1
+ require 'pp'
2
+
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
+
12
+ using NRSER
13
+
14
+ module NRSER::Types
15
+ # make a type.
16
+ def self.make value
17
+ if value.is_a? NRSER::Types::Type
18
+ value
19
+ elsif value.is_a? ::Class
20
+ IsA.new value
21
+ else
22
+ Is.new value
23
+ end
24
+ end
25
+
26
+ # raise an error if value doesn't match type.
27
+ def self.check value, type
28
+ make(type).check value
29
+ end
30
+
31
+ def self.test value, type
32
+ make(type).test value
33
+ end
34
+
35
+ def self.match value, type_map
36
+ type_map.each {|type, block|
37
+ if test value, type
38
+ return block.call value
39
+ end
40
+ }
41
+
42
+ raise TypeError, <<-END.dedent
43
+ could not match value
44
+
45
+ #{ value.inspect }
46
+
47
+ to any of types
48
+
49
+ #{ type_map.keys.map {|type| "\n #{ type.inspect }"} }
50
+
51
+ END
52
+ end
53
+
54
+ # make a type instance from a object representation that can come from
55
+ # a YAML or JSON declaration.
56
+ def self.from_repr repr
57
+ match repr, {
58
+ str => ->(string) {
59
+ NRSER::Types.method(string.downcase).call
60
+ },
61
+
62
+ Hash => ->(hash) {
63
+
64
+ },
65
+ }
66
+ end
67
+ end # NRSER::Types
68
+
69
+ # things that define values, which may need to call the functions defined
70
+ # above
71
+ require 'nrser/types/any'
72
+ require 'nrser/types/booleans'
73
+ require 'nrser/types/numbers'
74
+ require 'nrser/types/strings'
75
+ require 'nrser/types/array'
@@ -0,0 +1,13 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/where'
3
+
4
+ using NRSER
5
+
6
+ module NRSER::Types
7
+ ANY = where(name: 'Any', from_s: ->(s) { s }) { true }
8
+
9
+ # anything
10
+ def self.any
11
+ ANY
12
+ end
13
+ end # NRSER::Types
@@ -0,0 +1,61 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+ require 'nrser/types/is_a'
4
+
5
+ using NRSER
6
+
7
+ module NRSER::Types
8
+ class Array < IsA
9
+ SEP = /\,\s+/
10
+
11
+ attr_reader :item_type
12
+
13
+ def initialize item_type = NRSER::Types.any, **options
14
+ super ::Array, **options
15
+ @item_type = NRSER::Types.make item_type
16
+ end
17
+
18
+ def test value
19
+ super(value) && if @item_type == NRSER::Types.any
20
+ true
21
+ else
22
+ value.all? {|v| @item_type.test v}
23
+ end
24
+ end
25
+
26
+ def default_name
27
+ "#{ self.class.short_name }<#{ @item_type }>"
28
+ end
29
+
30
+ def has_from_s?
31
+ @item_class.has_from_s?
32
+ end
33
+
34
+ def from_s s
35
+ # does it looks like json?
36
+ if s.start_with? '['
37
+ begin
38
+ return JSON.load s
39
+ rescue
40
+ end
41
+ end
42
+
43
+ s.split SEP
44
+ end
45
+
46
+ def == other
47
+ equal?(other) || (
48
+ other.class == self.class && @item_type == other.item_type
49
+ )
50
+ end
51
+ end # Array
52
+
53
+ # array
54
+ def self.array *args
55
+ Array.new *args
56
+ end
57
+
58
+ def self.list
59
+ array
60
+ end
61
+ end # NRSER::Types
@@ -0,0 +1,69 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+ require 'nrser/types/combinators'
4
+
5
+ using NRSER
6
+
7
+ module NRSER::Types
8
+ class Attrs < NRSER::Types::Type
9
+ def initialize attrs, **options
10
+ super **options
11
+ @attrs = attrs
12
+ end
13
+
14
+ def default_name
15
+ attrs_str = @attrs.map {|name, type|
16
+ "#{ name }=#{ type.name }"
17
+ }.join(', ')
18
+
19
+ "#{ self.class.short_name }(#{ attrs_str })"
20
+ end
21
+
22
+ def test value
23
+ @attrs.all? {|name, type|
24
+ value.respond_to?(name) && type.test(value.method(name).call)
25
+ }
26
+ end
27
+ end # Attrs
28
+
29
+ def self.attrs attrs, options = {}
30
+ Attrs.new attrs, **options
31
+ end
32
+
33
+ def self.length *args
34
+ bounds = {}
35
+ options = {}
36
+
37
+ case args.length
38
+ when 1
39
+ case args[0]
40
+ when ::Integer
41
+ bounds[:min] = bounds[:max] = non_neg_int.check(args[0])
42
+
43
+ when ::Hash
44
+ options = args[0].reject {|k, v|
45
+ if k == :min || k == :max
46
+ bounds[k] = non_neg_int.check(v)
47
+ end
48
+ }
49
+
50
+ else
51
+ raise ArgumentError, <<-END.squish
52
+ arg must be positive integer or option hash, found:
53
+ #{ args[0].inspect } of type #{ args[0].class }
54
+ END
55
+ end
56
+
57
+ when 2
58
+ bounds[:min] = bounds[:max] = non_neg_int.check(args[0])
59
+ options = args[1]
60
+
61
+ else
62
+ raise ArgumentError, <<-END.squish
63
+ must provided 1 or 2 args.
64
+ END
65
+ end
66
+
67
+ attrs({length: intersection(non_neg_int, bounded(bounds))}, options)
68
+ end
69
+ end # NRSER::Types
@@ -0,0 +1,47 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+ require 'nrser/types/is'
4
+ require 'nrser/types/combinators'
5
+
6
+ using NRSER
7
+
8
+ module NRSER::Types
9
+ # booleans
10
+ # ========
11
+
12
+ TRUE = is true, name: 'true', from_s: ->(string) {
13
+ if ['true', 't', '1', 'yes', 'y', 'on'].include? string.downcase
14
+ true
15
+ else
16
+ raise TypeError, "can not convert to true: #{ string.inspect }"
17
+ end
18
+ }
19
+
20
+ def self.true
21
+ TRUE
22
+ end
23
+
24
+ FALSE = is false, name: 'false', from_s: ->(string) {
25
+ if ['false', 'f', '0', 'no', 'n', 'off'].include? string.downcase
26
+ false
27
+ else
28
+ raise TypeError, "can not convert to true: #{ string.inspect }"
29
+ end
30
+ }
31
+
32
+ def self.false
33
+ FALSE
34
+ end
35
+
36
+ BOOL = union TRUE, FALSE
37
+
38
+ # true or false
39
+ def self.bool
40
+ BOOL
41
+ end
42
+
43
+ def self.boolean
44
+ bool
45
+ end
46
+
47
+ end # NRSER::Types
@@ -0,0 +1,36 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+
4
+ using NRSER
5
+
6
+ module NRSER::Types
7
+ class Bounded < NRSER::Types::Type
8
+ def initialize **options
9
+ @min = options[:min]
10
+ @max = options[:max]
11
+ end
12
+
13
+ def test value
14
+ return false if @min && value < @min
15
+ return false if @max && value > @max
16
+ true
17
+ end
18
+
19
+ def default_name
20
+ attrs_str = ['min', 'max'].map {|name|
21
+ [name, instance_variable_get("@#{ name }")]
22
+ }.reject {|name, value|
23
+ value.nil?
24
+ }.map {|name, value|
25
+ "#{ name }=#{ value }"
26
+ }.join(', ')
27
+
28
+ "#{ self.class.short_name }(#{ attrs_str })"
29
+ end
30
+ end # Bounded
31
+
32
+ def self.bounded **options
33
+ Bounded.new **options
34
+ end
35
+
36
+ end # NRSER::Types
@@ -0,0 +1,86 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+
4
+ using NRSER
5
+
6
+ # base class for Union and Intersection which combine over a set of types.
7
+ module NRSER::Types
8
+ class Combinator < NRSER::Types::Type
9
+ attr_reader :types
10
+
11
+ def initialize *types, **options
12
+ super **options
13
+ @types = types.map {|type| NRSER::Types.make type}
14
+ end
15
+
16
+ def name
17
+ @name || (
18
+ "#{ self.class.short_name }(" +
19
+ @types.map {|type| type.name }.join(',') +
20
+ ")"
21
+ )
22
+ end
23
+
24
+ # a combinator may attempt to parse from a string if any of it's types
25
+ # can do so
26
+ def has_from_s?
27
+ @types.any? {|type| type.has_from_s?}
28
+ end
29
+
30
+ # a combinator iterates through each of it's types, trying the
31
+ # conversion and seeing if the result satisfies the combinator type
32
+ # itself. the first such value found is returned.
33
+ def from_s s
34
+ @types.each {|type|
35
+ if type.respond_to? :from_s
36
+ begin
37
+ return check type.from_s(s)
38
+ rescue TypeError => e
39
+ # pass
40
+ end
41
+ end
42
+ }
43
+
44
+ raise TypeError,
45
+ "none of union types could convert #{ string.inspect }"
46
+ end
47
+
48
+ def == other
49
+ equal?(other) || (
50
+ other.class == self.class && other.types == @types
51
+ )
52
+ end
53
+ end
54
+
55
+ class Union < Combinator
56
+ def test value
57
+ @types.any? {|type| type.test value}
58
+ end
59
+ end # Union
60
+
61
+ # match any of the types
62
+ def self.union *types, **options
63
+ NRSER::Types::Union.new *types, **options
64
+ end
65
+
66
+ # match any of the types
67
+ def self.one_of *types, **options
68
+ union *types, **options
69
+ end
70
+
71
+ class Intersection < Combinator
72
+ def test value
73
+ @types.all? {|type| type.test value}
74
+ end
75
+ end
76
+
77
+ # match all of the types
78
+ def self.intersection *types, **options
79
+ Intersection.new *types, **options
80
+ end
81
+
82
+ # match all of the types
83
+ def self.all_of *types, **options
84
+ intersection *types, **options
85
+ end
86
+ end # NRSER::Types
@@ -0,0 +1,15 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+
4
+ using NRSER
5
+
6
+ module NRSER::Types
7
+
8
+ class Hash < NRSER::Types::Type
9
+ attr_reader :keys, :values, :including, :exactly, :min, :max
10
+
11
+ def initialize options = {}
12
+
13
+ end
14
+ end # Hash
15
+ end
@@ -0,0 +1,33 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+ using NRSER
4
+
5
+ module NRSER::Types
6
+ class Is < NRSER::Types::Type
7
+ attr_reader :value
8
+
9
+ def initialize value, **options
10
+ super **options
11
+
12
+ @value = value
13
+ end
14
+
15
+ def name
16
+ "Is(#{ @value.inspect })"
17
+ end
18
+
19
+ def test value
20
+ @value.equal? value
21
+ end
22
+
23
+ def == other
24
+ equal?(other) || @value === other.value
25
+ end
26
+ end # Is
27
+
28
+ # an exact value (using ===)
29
+ def self.is value, **options
30
+ Is.new value, **options
31
+ end
32
+
33
+ end # NRSER::Types
@@ -0,0 +1,27 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+ using NRSER
4
+
5
+ module NRSER::Types
6
+ class IsA < NRSER::Types::Type
7
+ attr_reader :klass
8
+
9
+ def initialize klass, **options
10
+ super **options
11
+ @klass = klass
12
+ end
13
+
14
+ def name
15
+ @name || "#{ self.class.short_name }(#{ @klass })"
16
+ end
17
+
18
+ def test value
19
+ value.is_a? @klass
20
+ end
21
+ end # IsA
22
+
23
+ # class membership
24
+ def self.is_a klass
25
+ IsA.new klass
26
+ end
27
+ end # NRSER::Types
@@ -0,0 +1,11 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/combinators'
3
+
4
+ using NRSER
5
+
6
+ module NRSER::Types
7
+ # nil or the argument type
8
+ def self.maybe type
9
+ union nil, type, name: "Maybe(#{ type.name })"
10
+ end
11
+ end # NRSER::Types
@@ -0,0 +1,100 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/type'
3
+ require 'nrser/types/is_a'
4
+ require 'nrser/types/combinators'
5
+ require 'nrser/types/bounded'
6
+
7
+ using NRSER
8
+
9
+ module NRSER::Types
10
+ def self.parse_number s
11
+ float = s.to_f
12
+ int = float.to_i
13
+ if float == int then int else float end
14
+ end
15
+
16
+ # zero
17
+ # ====
18
+
19
+ ZERO = is 0, name: 'zero', from_s: method(:parse_number)
20
+
21
+ def self.zero
22
+ ZERO
23
+ end
24
+
25
+ # number (Numeric)
26
+ # ================
27
+
28
+ NUM = IsA.new Numeric, name: 'Num', from_s: method(:parse_number)
29
+
30
+ def self.num
31
+ NUM
32
+ end
33
+
34
+ # integers
35
+ # ========
36
+
37
+ INT = IsA.new Integer, name: 'Int', from_s: method(:parse_number)
38
+
39
+ def self.int
40
+ INT
41
+ end
42
+
43
+ def self.integer
44
+ int
45
+ end
46
+
47
+ # bounded integers
48
+ # ================
49
+ #
50
+
51
+ # positive integer
52
+ # ----------------
53
+ #
54
+ # integer greater than zero.
55
+ #
56
+
57
+ POS_INT = intersection INT, bounded(min: 1), name: 'PosInt'
58
+
59
+ def self.pos_int
60
+ POS_INT
61
+ end
62
+
63
+ # negative integer
64
+ # ----------------
65
+ #
66
+ # integer less than zero
67
+ #
68
+
69
+ NEG_INT = intersection INT, bounded(max: -1), name: 'NegInt'
70
+
71
+ def self.neg_int
72
+ NEG_INT
73
+ end
74
+
75
+ # non-negative integer
76
+ # --------------------
77
+ #
78
+ # positive integers and zero... but it seems more efficient to define these
79
+ # as bounded instead of a union.
80
+ #
81
+
82
+ NON_NEG_INT = intersection INT, bounded(min: 0), name: 'NonNegInt'
83
+
84
+ def self.non_neg_int
85
+ NON_NEG_INT
86
+ end
87
+
88
+ # non-positive integer
89
+ # --------------------
90
+ #
91
+ # negative integers and zero.
92
+ #
93
+
94
+ NON_POS_INT = intersection INT, bounded(max: 0), name: 'NonPosInt'
95
+
96
+ def self.non_pos_int
97
+ NON_POS_INT
98
+ end
99
+
100
+ end # NRSER::Types
@@ -0,0 +1,34 @@
1
+ require 'nrser/refinements'
2
+ require 'nrser/types/is'
3
+ require 'nrser/types/is_a'
4
+ require 'nrser/types/attrs'
5
+
6
+ using NRSER
7
+
8
+ module NRSER::Types
9
+ STR = IsA.new String, name: 'Str', from_s: ->(s) { s }
10
+
11
+ def self.str **options
12
+ if options.empty?
13
+ # if there are no options can point to the constant for efficiency
14
+ STR
15
+ else
16
+ types = []
17
+
18
+ if options[:length]
19
+ types << length(options[:length])
20
+ end
21
+
22
+ intersection STR, *types
23
+ end
24
+ end # string
25
+
26
+ def self.string
27
+ str
28
+ end
29
+
30
+ EMPTY_STR = Is.new ''
31
+
32
+ NON_EMPTY_STR = str length: {min: 1}, name: "NonEmptyStr"
33
+
34
+ end # NRSER::Types
@@ -0,0 +1,61 @@
1
+ require 'nrser/refinements'
2
+ using NRSER
3
+
4
+ module NRSER::Types
5
+ class Type
6
+ def self.short_name
7
+ name.split('::').last
8
+ end
9
+
10
+ def initialize **options
11
+ @name = options[:name]
12
+ @from_s = options[:from_s]
13
+ end
14
+
15
+ def name
16
+ @name || default_name
17
+ end
18
+
19
+ def default_name
20
+ self.class.short_name
21
+ end
22
+
23
+ def test value
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def check value
28
+ unless test value
29
+ raise TypeError.new NRSER.squish <<-END
30
+ value #{ value.inspect } failed check #{ self.inspect }
31
+ END
32
+ end
33
+
34
+ value
35
+ end
36
+
37
+ def respond_to? name, include_all = false
38
+ if name == :from_s || name == 'from_s'
39
+ has_from_s?
40
+ else
41
+ super name, include_all
42
+ end
43
+ end
44
+
45
+ def from_s s
46
+ if @from_s.nil?
47
+ raise NoMethodError, "#from_s not defined"
48
+ end
49
+
50
+ check @from_s.(s)
51
+ end
52
+
53
+ def has_from_s?
54
+ ! @from_s.nil?
55
+ end
56
+
57
+ def to_s
58
+ "<Type:#{ name }>"
59
+ end
60
+ end # Type
61
+ end # NRSER::Types
@@ -0,0 +1,22 @@
1
+ require 'nrser/refinements'
2
+ using NRSER
3
+
4
+ module NRSER::Types
5
+ class Where < NRSER::Types::Type
6
+ attr_reader :predicate
7
+
8
+ def initialize predicate, **options
9
+ super **options
10
+ @predicate = predicate
11
+ end
12
+
13
+ def test value
14
+ !!@predicate.call(value)
15
+ end
16
+ end # Where
17
+
18
+ # create a type based on a predicate
19
+ def self.where **options, &block
20
+ Where.new block, **options
21
+ end
22
+ end # NRSER::Types
data/lib/nrser/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module NRSER
2
- VERSION = "0.0.15"
2
+ VERSION = "0.0.16"
3
3
  end
@@ -3,39 +3,39 @@ require 'spec_helper'
3
3
  using NRSER
4
4
 
5
5
  describe 'NRSER::Logger#die' do
6
- it "prints the log message when logger is off" do
7
- src = <<-END.dedent
8
- require 'nrser/logger'
9
-
10
- NRSER::Logger.install self
11
-
12
- die "die!", cause: "just 'cause"
13
- END
14
-
15
- err = Cmds.err("bundle exec ruby"){ src }
16
- data = YAML.load(err)['FATAL']
17
-
18
- expect(data['msg']).to eq 'die!'
19
- expect(data['values']).to eq({'cause' => "just 'cause"})
20
- end
21
-
22
- it(
23
- "prints only to the log when it's on and the log writes to " +
24
- "$stderr"
25
- ) do
26
- src = <<-END
27
- require 'nrser/logger'
28
-
29
- NRSER::Logger.install self, on: true, say_hi: false
30
-
31
- die "die!", cause: "just 'cause"
32
- END
33
-
34
- err = Cmds.err("bundle exec ruby"){ src }
35
-
36
- data = YAML.load(err)['FATAL']
37
-
38
- expect(data['msg']).to eq 'die!'
39
- expect(data['values']).to eq({'cause' => "just 'cause"})
40
- end
6
+ # it "prints the log message when logger is off" do
7
+ # src = <<-END.dedent
8
+ # require 'nrser/logger'
9
+ #
10
+ # NRSER::Logger.install self
11
+ #
12
+ # die "die!", cause: "just 'cause"
13
+ # END
14
+ #
15
+ # err = Cmds.err("bundle exec ruby"){ src }
16
+ # data = YAML.load(err)['FATAL']
17
+ #
18
+ # expect(data['msg']).to eq 'die!'
19
+ # expect(data['values']).to eq({'cause' => "just 'cause"})
20
+ # end
21
+ #
22
+ # it(
23
+ # "prints only to the log when it's on and the log writes to " +
24
+ # "$stderr"
25
+ # ) do
26
+ # src = <<-END
27
+ # require 'nrser/logger'
28
+ #
29
+ # NRSER::Logger.install self, on: true, say_hi: false
30
+ #
31
+ # die "die!", cause: "just 'cause"
32
+ # END
33
+ #
34
+ # err = Cmds.err("bundle exec ruby"){ src }
35
+ #
36
+ # data = YAML.load(err)['FATAL']
37
+ #
38
+ # expect(data['msg']).to eq 'die!'
39
+ # expect(data['values']).to eq({'cause' => "just 'cause"})
40
+ # end
41
41
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'nrser/refinements'
3
+
4
+ using NRSER
5
+
6
+ describe 'Pathname' do
7
+
8
+ describe '#start_with?' do
9
+ it "works with other Pathname instances" do
10
+ expect(
11
+ Pathname.new('a/b/c').start_with? Pathname.new('a/b')
12
+ ).to be true
13
+
14
+ expect(
15
+ Pathname.new('a/b/c').start_with? Pathname.new('a/b/')
16
+ ).to be true
17
+
18
+ expect(
19
+ Pathname.new('/a/b/c').start_with? Pathname.new('/')
20
+ ).to be true
21
+ end
22
+ end # #start_with?
23
+
24
+ describe '#sub' do
25
+ context "other pathnames" do
26
+ it "works for basic replacement" do
27
+ expect(
28
+ Pathname.new('a/b/c').sub Pathname.new('a/b'), 'c/d'
29
+ ).to eq Pathname.new('c/d/c')
30
+ end
31
+
32
+ it "only substitutes the first occurrence" do
33
+ expect(
34
+ Pathname.new('c/c/c').sub Pathname.new('c'), 'a'
35
+ ).to eq Pathname.new('a/c/c')
36
+ end
37
+ end
38
+ end
39
+
40
+ end # Pathname
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe NRSER::Types::Union do
4
+ t = NRSER::Types
5
+
6
+ describe '==' do
7
+ it "equates two different instances with equal types" do
8
+ expect(t.union 1, 2, 3).to eq t.union(1, 2, 3)
9
+ end
10
+ end
11
+ end # NRSER::Types::Union
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe NRSER::Types::Is do
4
+ t = NRSER::Types
5
+
6
+ describe '==' do
7
+ it "equates two different instances with equal types" do
8
+ expect(t.is 1).to eq t.is(1)
9
+ expect([t.is(1)]).to eq [t.is(1)]
10
+ end
11
+ end
12
+ end # NRSER::Types::Union
@@ -0,0 +1,197 @@
1
+ require 'spec_helper'
2
+
3
+ describe NRSER::Types do
4
+ t = NRSER::Types
5
+
6
+ describe 'basic types #test and #check' do
7
+ {
8
+ t.any => {
9
+ pass: [nil, 'blah', 1, 3.14, [], {}, Object.new],
10
+ from_s: {
11
+ pass: ['hey', 'ho', "let's go"],
12
+ },
13
+ },
14
+
15
+ t.is(1) => {
16
+ pass: [1],
17
+ fail: [2, '1', nil, true],
18
+ },
19
+
20
+ t.is_a(Array) => {
21
+ pass: [[]],
22
+ fail: [{}],
23
+ },
24
+
25
+ t.true => {
26
+ pass: [true],
27
+ fail: [1, 'true'],
28
+ },
29
+
30
+ t.false => {
31
+ pass: [false],
32
+ fail: [true, 0, nil, 'false'],
33
+ },
34
+
35
+ t.bool => {
36
+ pass: [true, false],
37
+ fail: [0, 1, nil],
38
+ },
39
+
40
+ t.int => {
41
+ pass: [0, 1, -1, 888],
42
+ fail: ['0', 3.14],
43
+ from_s: {
44
+ pass: ['1', '10', '0', '-1', '1000000000000000000000'],
45
+ fail: ['3.14', '1more', 'hey'],
46
+ }
47
+ },
48
+
49
+ t.pos_int => {
50
+ pass: [1, 10, 1000000000000000000000],
51
+ fail: [0, -1],
52
+ from_s: {
53
+ pass: ['1', '10', '1000000000000000000000'],
54
+ fail: ['0', '-1', '3.14'],
55
+ }
56
+ },
57
+
58
+ t.neg_int => {
59
+ pass: [-1, -10, -1000000000000000000000],
60
+ fail: [0, 1],
61
+ from_s: {
62
+ pass: ['-1', '-10', '-1000000000000000000000'],
63
+ fail: ['0', '1', '3.14'],
64
+ }
65
+ },
66
+
67
+ t.non_neg_int => {
68
+ pass: [0, 1],
69
+ fail: [nil, -1, false],
70
+ from_s: {
71
+ pass: ['0', '1'],
72
+ fail: ['-1'],
73
+ },
74
+ },
75
+
76
+ t.non_pos_int => {
77
+ pass: [0, -1],
78
+ fail: [1],
79
+ from_s: {
80
+ pass: ['0', '-1'],
81
+ fail: ['1', 'blah'],
82
+ },
83
+ },
84
+
85
+ t.str => {
86
+ pass: ['hey', ''],
87
+ fail: [1, {}, nil],
88
+ from_s: {
89
+ pass: ['hey', ''],
90
+ }
91
+ },
92
+
93
+ t.attrs(to_s: t.str) => {
94
+ pass: [''],
95
+ },
96
+
97
+ t.length(min: 0, max: 0) => {
98
+ pass: ['', [], {}],
99
+ fail: ['x', [1], {x: 1}],
100
+ },
101
+
102
+ t.length(0) => {
103
+ pass: ['', [], {}],
104
+ fail: ['x', [1], {x: 1}],
105
+ },
106
+
107
+ t.bounded(min: 0, max: 0) => {
108
+ pass: [0],
109
+ },
110
+
111
+ t.union(t.non_neg_int, t.bounded(min: 0, max: 0)) => {
112
+ pass: [0],
113
+ },
114
+
115
+ t.attrs(length: t.bounded(min: 0, max: 0)) => {
116
+ pass: ['', []],
117
+ fail: ['hey'],
118
+ },
119
+
120
+ t.str(length: 0) => {
121
+ pass: [''],
122
+ fail: ['hey'],
123
+ },
124
+
125
+ t.array => {
126
+ pass: [[], [1, 2, 3]],
127
+ fail: [nil, {}, '1,2,3'],
128
+ from_s: {
129
+ pass: ['1,2,3', '', '[1,2,3]', 'a, b, c'],
130
+ }
131
+ },
132
+
133
+ t.array(t.int) => {
134
+ pass: [[], [1, 2, 3]],
135
+ fail: [['1']],
136
+ from_s: {
137
+ pass: ['1,2,3', '', '[1,2,3]'],
138
+ fail: ['a,b,c'],
139
+ }
140
+ },
141
+
142
+ }.each do |type, tests|
143
+ if tests[:pass]
144
+ tests[:pass].each do |value|
145
+ it "ACCEPS #{ value.inspect } as #{ type }" do
146
+ expect(type.test value).to be true
147
+ expect {type.check value}.not_to raise_error
148
+ end
149
+ end
150
+ end
151
+
152
+ if tests[:fail]
153
+ tests[:fail].each do |value|
154
+ it "REJECTS #{ value.inspect } as #{ type }" do
155
+ expect(type.test value).to be false
156
+ expect {type.check value}.to raise_error TypeError
157
+ end
158
+ end
159
+ end
160
+
161
+ if tests[:from_s]
162
+ if tests[:from_s][:pass]
163
+ tests[:from_s][:pass].each do |string|
164
+ unless string.is_a? String
165
+ raise "must be string: #{ string.inspect }"
166
+ end
167
+
168
+ it "#{ type }#from_s ACCEPTS string #{ string.inspect }" do
169
+ expect{ type.from_s string }.not_to raise_error
170
+ end
171
+ end
172
+ end
173
+ end # from_s
174
+ end # each
175
+ end # basic types #test and #check
176
+
177
+ describe ".from_repr" do
178
+ {
179
+ t.str => ['string', 'str', 'String', 'STRING', 'STR'],
180
+ t.int => ['int', 'integer', 'Integer', 'INT'],
181
+ t.bool => ['bool', 'boolean', 'Boolean', 'BOOL'],
182
+ t.array => ['array', 'list', 'Array'],
183
+ # t.union('a', 'b', 'c') => [
184
+ # {
185
+ # 'one_of': ['a', 'b', 'c'],
186
+ # }
187
+ # ]
188
+ }.each do |type, inputs|
189
+ inputs.each do |input|
190
+ it "converts #{ input.inspect } to #{ type }" do
191
+ expect(NRSER::Types.from_repr input).to eq type
192
+ end
193
+ end
194
+ end
195
+ end # #from_repr
196
+
197
+ end # QB::Types
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.15
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - nrser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-13 00:00:00.000000000 Z
11
+ date: 2017-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -98,6 +98,21 @@ files:
98
98
  - lib/nrser/collection.rb
99
99
  - lib/nrser/logger.rb
100
100
  - lib/nrser/refinements.rb
101
+ - lib/nrser/types.rb
102
+ - lib/nrser/types/any.rb
103
+ - lib/nrser/types/array.rb
104
+ - lib/nrser/types/attrs.rb
105
+ - lib/nrser/types/booleans.rb
106
+ - lib/nrser/types/bounded.rb
107
+ - lib/nrser/types/combinators.rb
108
+ - lib/nrser/types/hash.rb
109
+ - lib/nrser/types/is.rb
110
+ - lib/nrser/types/is_a.rb
111
+ - lib/nrser/types/maybe.rb
112
+ - lib/nrser/types/numbers.rb
113
+ - lib/nrser/types/strings.rb
114
+ - lib/nrser/types/type.rb
115
+ - lib/nrser/types/where.rb
101
116
  - lib/nrser/version.rb
102
117
  - nrser.gemspec
103
118
  - spec/nrser/collection/each_spec.rb
@@ -117,9 +132,13 @@ files:
117
132
  - spec/nrser/refinements/erb_spec.rb
118
133
  - spec/nrser/refinements/format_exception_spec.rb
119
134
  - spec/nrser/refinements/indent_spec.rb
135
+ - spec/nrser/refinements/pathname_spec.rb
120
136
  - spec/nrser/refinements/truncate_spec.rb
121
137
  - spec/nrser/template_spec.rb
122
138
  - spec/nrser/truncate_spec.rb
139
+ - spec/nrser/types/combinators_spec.rb
140
+ - spec/nrser/types/is_spec.rb
141
+ - spec/nrser/types_spec.rb
123
142
  - spec/nrser_spec.rb
124
143
  - spec/spec_helper.rb
125
144
  - tmp/.gitkeep
@@ -143,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
162
  version: '0'
144
163
  requirements: []
145
164
  rubyforge_project:
146
- rubygems_version: 2.2.2
165
+ rubygems_version: 2.6.11
147
166
  signing_key:
148
167
  specification_version: 4
149
168
  summary: basic ruby utils i use in a lot of stuff.
@@ -165,9 +184,12 @@ test_files:
165
184
  - spec/nrser/refinements/erb_spec.rb
166
185
  - spec/nrser/refinements/format_exception_spec.rb
167
186
  - spec/nrser/refinements/indent_spec.rb
187
+ - spec/nrser/refinements/pathname_spec.rb
168
188
  - spec/nrser/refinements/truncate_spec.rb
169
189
  - spec/nrser/template_spec.rb
170
190
  - spec/nrser/truncate_spec.rb
191
+ - spec/nrser/types/combinators_spec.rb
192
+ - spec/nrser/types/is_spec.rb
193
+ - spec/nrser/types_spec.rb
171
194
  - spec/nrser_spec.rb
172
195
  - spec/spec_helper.rb
173
- has_rdoc: