nrser 0.0.15 → 0.0.16

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
  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: