inquisitive 3.1.0 → 3.1.1

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: e22f450e21c1139aff9b5587f6da20f9964ed3f5
4
- data.tar.gz: 26d9737845ee0028316664d7715ec0b2457619b1
3
+ metadata.gz: 78b5345c827669dee4928a4907d68799180a7b6a
4
+ data.tar.gz: 39899a19a8e7701645acc4134d1c1f8d4e7af5a0
5
5
  SHA512:
6
- metadata.gz: 213264cbb822921b64d7393fcdeee3c135dbee7e4ae4ed93d9150b01354fe6f0803d4028cc2ad64147ccf47239de5c2ec49121a60338911beec8dc4d697dc561
7
- data.tar.gz: eea7a7c74d2a3288e6902b1012bccefbaec395e7847007d1dd87fa1cfaa109bdea7d9bcf00ea41af33f36115c504e28059bf6be4ceac90f2b7750aaa0c877e65
6
+ metadata.gz: 0a8a2423a9dccc219ac6d3dd13fc9d953e827a83cf6aa089e6dec24deaf21e171c73f4e4b130e7472c3c4467ad4cd821bf75450c13f028096df95153f806580a
7
+ data.tar.gz: aae5568da7e1a36a75adbc0573fa7a2a3c26b2ef543deee13f1c44631870e752e2710d441603004fed126ca2b7bcf419ae82ca38f93d6249ff7542012bc45349
data/README.md CHANGED
@@ -10,7 +10,7 @@ Synopsis
10
10
 
11
11
  Inquisitive provides String, Array, and Hash subclasses with dynamic predicate methods that allow you to interrogate the most common Ruby datastructures in a readable, friendly fashion. It's the inevitable evolution of ActiveSupport's `StringInquirer`.
12
12
 
13
- It also allows you to auto-instanciate and read inquisitive datastructures straight from your `ENV` hash through the `Inquisitive::Environment` module.
13
+ It also allows you to elegantly interrogate your `ENV` hash through the `Inquisitive::Environment` module.
14
14
 
15
15
  Inquisitive will try to use ActiveSupport's `HashWithIndifferentAccess`, but if that cannot be found it will bootstrap itself with a minimal, well-tested version extracted from ActiveSupport 4.0.
16
16
 
@@ -70,6 +70,92 @@ Usage
70
70
  -----
71
71
 
72
72
 
73
+ ### Helpers
74
+
75
+ You can coerce any object to a supported Inquisitive equivalent with the Inquisitive coercion helpers:
76
+
77
+ ```ruby
78
+ Inquisitive.coerce('foo').class
79
+ #=> Inquisitive::String
80
+ Inquisitive.coerce(1).class
81
+ #=> Integer
82
+
83
+ Inquisitive['foo'].class
84
+ #=> Inquisitive::String
85
+ Inquisitive[1].class
86
+ #=> Integer
87
+
88
+ Inquisitive.coerce!('foo').class
89
+ #=> Inquisitive::String
90
+ Inquisitive.coerce!(1).class
91
+ #=> NameError
92
+ ```
93
+
94
+ You can check if any object appears to be present with the Inquisitive presence helper:
95
+
96
+ ```ruby
97
+ Inquisitive.present? 'foo'
98
+ #=> true
99
+ Inquisitive.present? %i[foo]
100
+ #=> true
101
+ Inquisitive.present? {foo: :bar}
102
+ #=> true
103
+ Inquisitive.present? 0
104
+ #=> true
105
+ Inquisitive.present? true
106
+ #=> true
107
+
108
+ Inquisitive.present? ''
109
+ #=> false
110
+ Inquisitive.present? Array.new
111
+ #=> false
112
+ Inquisitive.present? Hash.new
113
+ #=> false
114
+ Inquisitive.present? false
115
+ #=> false
116
+ Inquisitive.present? nil
117
+ #=> false
118
+ Inquisitive.present? Inquisitive::NilClass.new
119
+ #=> false
120
+ ```
121
+
122
+ Finally, you can check if any object is explicitly an Inquisitive object with the Inquisitive object helper:
123
+
124
+ ```ruby
125
+ nil_object = nil
126
+ Inquisitive.object? nil_object
127
+ #=> false
128
+ Inquisitive.object? Inquisitive[nil_object]
129
+ #=> true
130
+ Inquisitive.object? Inquisitive::NilClass.new nil_object
131
+ #=> true
132
+
133
+ string = 'foo'
134
+ Inquisitive.object? string
135
+ #=> false
136
+ Inquisitive.object? Inquisitive[string]
137
+ #=> true
138
+ Inquisitive.object? Inquisitive::String.new string
139
+ #=> true
140
+
141
+ array = %i[foo]
142
+ Inquisitive.object? array
143
+ #=> false
144
+ Inquisitive.object? Inquisitive[array]
145
+ #=> true
146
+ Inquisitive.object? Inquisitive::Array.new array
147
+ #=> true
148
+
149
+ hash = {foo: :bar}
150
+ Inquisitive.object? hash
151
+ #=> false
152
+ Inquisitive.object? Inquisitive[hash]
153
+ #=> true
154
+ Inquisitive.object? Inquisitive::Hash.new hash
155
+ #=> true
156
+ ```
157
+
158
+
73
159
  ### String
74
160
 
75
161
  `Inquisitive::String` tests equality:
@@ -212,6 +298,35 @@ stubbed.api.domains.web?
212
298
  #=> false
213
299
  ```
214
300
 
301
+ This custom `Inquisitive::NilClass` comes with a few caveats, read the section below to understand them.
302
+
303
+
304
+ ### NilClass
305
+
306
+ `Inquisitive::NilClass` is a black-hole null object that respects the Inquisitive interface, allowing you to inquire on non-existant nested datastructures as if there was one there, negated methods included:
307
+
308
+ ```ruby
309
+ nillish = Inquisitive::NilClass.new
310
+ #=> nil
311
+
312
+ nillish.nil?
313
+ #=> true
314
+ nillish.present?
315
+ #=> false
316
+
317
+
318
+ nillish.access
319
+ #=> nil
320
+ nillish.not.access
321
+ #=> true
322
+ nillish.exclude.access
323
+ #=> true
324
+ nillish.no.access
325
+ #=> true
326
+ ```
327
+
328
+ **Be warned**: since Ruby doesn't allow subclassing `NilClass` and provides no boolean-coercion mechanism, `Inquisitive::NilClass` **will** appear truthy. I recommend using built-in predicates (`stubbed.authentication? && ...`), presence predicates with ActiveSupport (`stubbed.authentication.present? && ...`), Inquisitive's presence utility (`Inquisitive.present?(stubbed.authentication) && ...`) or nil predicates (`stubbed.authentication.nil? || ...`) in boolean chains. Also note that for `Inquisitive::Hash` access, `stubbed.fetch(:authentication, ...)` behaves as expected.
329
+
215
330
 
216
331
  ### Inquisitive Environment
217
332
 
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "inquisitive"
7
- spec.version = "3.1.0"
7
+ spec.version = "3.1.1"
8
8
  spec.authors = ["Chris Keele"]
9
9
  spec.email = ["dev@chriskeele.com"]
10
10
  spec.summary = "Predicate methods for those curious about their datastructures."
@@ -2,11 +2,20 @@ module Inquisitive
2
2
 
3
3
  class << self
4
4
 
5
- def [](object)
6
- Inquisitive.const_get(:"#{object.class}", false).new object
5
+ def coerce(object)
6
+ coerce! object
7
7
  rescue NameError
8
8
  object
9
9
  end
10
+ alias_method :[], :coerce
11
+
12
+ def coerce!(object)
13
+ if Inquisitive.object? object
14
+ object
15
+ else
16
+ Inquisitive.const_get(:"#{object.class}", false).new object
17
+ end
18
+ end
10
19
 
11
20
  def present?(object)
12
21
  case object
@@ -23,20 +32,34 @@ module Inquisitive
23
32
  when ::NilClass, NilClass
24
33
  false
25
34
  else
26
- !!object
35
+ if object.respond_to?(:present?)
36
+ object.present?
37
+ else
38
+ !!object
39
+ end
27
40
  end
28
41
  end
29
42
 
43
+ def object?(object)
44
+ object.class.name.start_with? 'Inquisitive::'
45
+ end
46
+
30
47
  end
31
48
 
32
49
  private
33
50
 
34
- def predicate_method?(string)
35
- string[-1] == '?'
36
- end
51
+ module Utils
52
+
53
+ private
54
+
55
+ def predicate_method?(string)
56
+ string[-1] == '?'
57
+ end
58
+
59
+ def predication(string)
60
+ string[0..-2]
61
+ end
37
62
 
38
- def predication(string)
39
- string[0..-2]
40
63
  end
41
64
 
42
65
  end
@@ -1,6 +1,6 @@
1
1
  module Inquisitive
2
2
  class Array < ::Array
3
- include Inquisitive
3
+ include Inquisitive::Utils
4
4
 
5
5
  attr_accessor :negated
6
6
  def exclude
@@ -1,6 +1,6 @@
1
1
  module Inquisitive
2
2
  module Environment
3
- include Inquisitive
3
+ include Inquisitive::Utils
4
4
 
5
5
  def truthy
6
6
  /true|yes|1/i
@@ -80,7 +80,7 @@ module Inquisitive
80
80
 
81
81
  def can_find_env_keys_from(var_name)
82
82
  found = env_keys_from(var_name)
83
- found.empty? ? nil : found
83
+ Inquisitive.present?(found) ? found : nil
84
84
  end
85
85
 
86
86
  def env_keys_from(var_name)
@@ -91,24 +91,26 @@ module Inquisitive
91
91
 
92
92
  def set_hash_value_of(hash, var)
93
93
  keypath = var.split('__').map(&:downcase)
94
- keypath.shift
94
+ keypath.shift # discard variable namespace
95
95
  hash.tap do |hash|
96
96
  keypath.reduce(hash) do |namespace, key|
97
+
97
98
  namespace[key] = if key == keypath.last
98
99
  replace_empty Inquisitive[Parser[var]]
99
100
  else
100
- if namespace[key].respond_to? :store
101
+ if namespace[key].kind_of? ::Hash
101
102
  namespace[key]
102
103
  else
103
104
  Hash.new
104
105
  end
105
106
  end
107
+
106
108
  end
107
109
  end
108
110
  end
109
111
 
110
112
  def replace_empty(value)
111
- value == "" or value.nil? ? NilClass.new(nil) : value
113
+ Inquisitive.present?(value) ? value : NilClass.new(nil)
112
114
  end
113
115
 
114
116
  end
@@ -1,20 +1,44 @@
1
1
  module Inquisitive
2
2
  class Hash < HashWithIndifferentAccess
3
- include Inquisitive
3
+ include Inquisitive::Utils
4
4
 
5
5
  attr_accessor :negated
6
6
  def no
7
7
  dup.tap{ |s| s.negated = !s.negated }
8
8
  end
9
9
 
10
- def convert_value(value, options={})
11
- super(Inquisitive[value], options)
12
- end
13
-
14
10
  def === other
15
11
  other.class == Class and other == ::Hash or super
16
12
  end
17
13
 
14
+ alias_method :regular_reader, :[] unless method_defined?(:regular_reader)
15
+ def [](key)
16
+ Inquisitive[regular_reader key]
17
+ end
18
+
19
+ def fetch(key, default=nil)
20
+ key = convert_key(key)
21
+ value = self[key]
22
+ if Inquisitive.present? value
23
+ value
24
+ else
25
+ if block_given?
26
+ yield(key)
27
+ else
28
+ default
29
+ end
30
+ end
31
+ end
32
+
33
+ protected
34
+
35
+ def convert_value(value, options={})
36
+ if options[:for] == :assignment
37
+ return if value.kind_of? NilClass
38
+ end
39
+ super(Inquisitive[value], options)
40
+ end
41
+
18
42
  private
19
43
 
20
44
  def dup
@@ -1,6 +1,6 @@
1
1
  module Inquisitive
2
2
  class NilClass
3
- include Inquisitive
3
+ include Inquisitive::Utils
4
4
 
5
5
  def initialize(object=nil); end
6
6
 
@@ -13,6 +13,10 @@ module Inquisitive
13
13
 
14
14
  undef_method :nil?, :inspect, :to_s
15
15
 
16
+ def present?
17
+ presence
18
+ end
19
+
16
20
  # Since we can't subclass NilClass
17
21
  # (it has no allocate method)
18
22
  # we fake its identity.
@@ -38,11 +42,15 @@ module Inquisitive
38
42
  if nil.respond_to? method_name
39
43
  nil.send method_name, *arguments
40
44
  elsif predicate_method? method_name
41
- false ^ negated
45
+ presence
42
46
  else
43
47
  self
44
48
  end
45
49
  end
46
50
 
51
+ def presence
52
+ false ^ negated
53
+ end
54
+
47
55
  end
48
56
  end
@@ -1,6 +1,6 @@
1
1
  module Inquisitive
2
2
  class String < ::String
3
- include Inquisitive
3
+ include Inquisitive::Utils
4
4
 
5
5
  attr_accessor :negated
6
6
  def not
@@ -23,6 +23,7 @@ class InquisitiveCombinatorialEnvironmentTest < EnvironmentTest
23
23
  ENV.delete 'HASH__IN'
24
24
  ENV.delete 'HASH__DATABASES'
25
25
  ENV.delete 'HASH__NESTED__KEY'
26
+ ENV.delete 'HASH__NESTED__ARRAY'
26
27
  ENV.delete 'HASH__SOMETHING_NEW'
27
28
  end
28
29
 
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class InquisitiveTest < Test
4
- Helpers = Module.new.extend Inquisitive
4
+ Utils = Module.new.extend Inquisitive::Utils
5
5
  HashWithIndifferentAccess ||= Inquisitive::HashWithIndifferentAccess
6
6
 
7
7
  def setup
@@ -147,25 +147,25 @@ class InquisitiveTest < Test
147
147
  end
148
148
 
149
149
  ####
150
- # HELPERS
150
+ # UTILS
151
151
  ##
152
152
  def test_found_symbol_predicate_method_helper
153
- assert Helpers.send :predicate_method?, :foo?
153
+ assert Utils.send :predicate_method?, :foo?
154
154
  end
155
155
  def test_found_string_predicate_method_helper
156
- assert Helpers.send :predicate_method?, "foo?"
156
+ assert Utils.send :predicate_method?, "foo?"
157
157
  end
158
158
  def test_missing_symbol_predicate_method_helper
159
- refute Helpers.send :predicate_method?, :foo
159
+ refute Utils.send :predicate_method?, :foo
160
160
  end
161
161
  def test_missing_string_predicate_method_helper
162
- refute Helpers.send :predicate_method?, "foo"
162
+ refute Utils.send :predicate_method?, "foo"
163
163
  end
164
164
 
165
165
  def test_symbol_predication_helper
166
- assert_equal Helpers.send(:predication, :foo?), 'foo'
166
+ assert_equal Utils.send(:predication, :foo?), 'foo'
167
167
  end
168
168
  def test_string_predication_helper
169
- assert_equal Helpers.send(:predication, "foo?"), 'foo'
169
+ assert_equal Utils.send(:predication, "foo?"), 'foo'
170
170
  end
171
171
  end
@@ -10,22 +10,48 @@ module HashTests
10
10
  refute hash.registration?
11
11
  end
12
12
 
13
- def test_hash_access_implicit_nil
13
+ def test_hash_method_access_implicit_nil
14
14
  assert_instance_of Inquisitive::NilClass, hash.missing_key
15
15
  end
16
- def test_hash_access_explicit_nil
16
+ def test_hash_method_access_explicit_nil
17
17
  assert_instance_of Inquisitive::NilClass, hash.nothing
18
18
  end
19
- def test_hash_access_string
19
+ def test_hash_method_access_string
20
20
  assert_instance_of Inquisitive::String, hash.in
21
21
  end
22
- def test_hash_access_array
22
+ def test_hash_method_access_array
23
23
  assert_instance_of Inquisitive::Array, hash.databases
24
24
  end
25
- def test_hash_access_hash
25
+ def test_hash_method_access_hash
26
26
  assert_instance_of Inquisitive::Hash, hash.nested
27
27
  end
28
28
 
29
+ def test_hash_access_implicit_nil
30
+ assert_instance_of Inquisitive::NilClass, hash[:missing_key]
31
+ end
32
+ def test_hash_access_explicit_nil
33
+ assert_instance_of Inquisitive::NilClass, hash[:nothing]
34
+ end
35
+ def test_hash_access_string
36
+ assert_instance_of Inquisitive::String, hash[:in]
37
+ end
38
+ def test_hash_access_array
39
+ assert_instance_of Inquisitive::Array, hash[:databases]
40
+ end
41
+ def test_hash_access_hash
42
+ assert_instance_of Inquisitive::Hash, hash[:nested]
43
+ end
44
+
45
+ def test_hash_fetch_implicit_nil
46
+ assert_equal hash.fetch(:missing_key, @default_value), @default_value
47
+ end
48
+ def test_hash_fetch_explicit_nil
49
+ assert_equal hash.fetch(:nothing, @default_value), @default_value
50
+ end
51
+ def test_hash_present_value
52
+ assert_equal hash.fetch(:in), @raw_string
53
+ end
54
+
29
55
  def test_hash_negative_match
30
56
  assert hash.no.registration?
31
57
  end
@@ -56,6 +56,7 @@ class Test < MiniTest::Test
56
56
  databases: @raw_array,
57
57
  nested: {key: 'value', array: %w[foo bar]}
58
58
  }
59
+ @default_value = 'foo'
59
60
  end
60
61
 
61
62
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inquisitive
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Keele