inquisitive 1.2.0 → 2.0.0

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: 0386fe6dcde04e8963c090b8b2e937003cd0f23a
4
- data.tar.gz: fd157641b836c285be3f496e644d25eedd2dc8ca
3
+ metadata.gz: 82f138341b19063e39338834d96ff3cd4bb479e1
4
+ data.tar.gz: d518c1b744f8ac23092a992b39cf38cc49ffb97b
5
5
  SHA512:
6
- metadata.gz: 7bdaac4757a5166432c9a0af4b31d78d33d07498a7ce6ee2b2d5b9daedb0a58c581a6f7e6edcf5fd906c955030f13fe34dc81d05fd3ecef953e3dc7961a0cef0
7
- data.tar.gz: 429c3aed3a0de7a9c99ef3ebce6d381baab13c9b577d7678954000a40e6b3b264e0ffdf4142c818a312d68a11cd2a3292695d247c7ab4ebb260c77983011c201
6
+ metadata.gz: 829304a8b3326698f81ce23868356a969578344ac7b93d39ed59687269a0574c095ce9cee48e11fc8c2216e99bff06339ab8da0d5ef76cc73827ce682f070e82
7
+ data.tar.gz: cd501e9fbb4651689562457adc90b1f94bd0e076caf70c150550e1019788aaa2eef8e56d7ab1b8d81dd786c772fcd9cdb237c76eba62c7a458c0c48c032b0dba
@@ -0,0 +1,69 @@
1
+ Changes to Inquisitive
2
+ ======================
3
+
4
+ > **Please consult this file when upgrading Inquisitive for important information on bugfixes, new features, and backwards incompatible changes.**
5
+
6
+ Starting with **[2.0.0](#2.0.0)**, Inquisitive follows [symantic versioning](symver.org) to help inform you of the implications of upgrades.
7
+
8
+ Releases
9
+ --------
10
+
11
+ [2.0.0]: https://github.com/christhekeele/inquisitive/tree/2.0.0
12
+ [1.2.0]: https://github.com/christhekeele/inquisitive/tree/f314eaf84f7c3d9a2d56ae684d031dd81d2f7b85
13
+
14
+ - [2.0.0](#2.0.0)
15
+ - [1.2.0](#1.2.0)
16
+
17
+ 2.0.0 - [2014.06.19][2.0.0]
18
+ ---------------------------
19
+
20
+ ### Breaking
21
+
22
+ - `Inquisitive::Environment`: **hash detection**
23
+
24
+ Previously `inquires_about` needed a special syntax to detect when you want to parse a group of environment variables as a hash. This was accomplished by leaving a trailing `_` in the declaration, such as:
25
+
26
+ ```ruby
27
+ ENV['PREFIX_KEY1'] = "value1"
28
+ ENV['PREFIX_KEY2'] = "value2"
29
+ module Mine
30
+ extend Inquisitive::Environment
31
+ inquires_about 'PREFIX_'
32
+ end
33
+ Mine.prefix
34
+ #=> { 'key1' => 'value1', 'key2' => 'value2' }
35
+ ```
36
+
37
+ Now it auto-detects hash groupings by looking for a double-`_` in the key itself:
38
+
39
+ ```ruby
40
+ ENV['PREFIX__KEY1'] = "value1"
41
+ ENV['PREFIX__KEY2'] = "value2"
42
+ module Mine
43
+ extend Inquisitive::Environment
44
+ inquires_about 'PREFIX'
45
+ end
46
+ Mine.prefix
47
+ #=> { 'key1' => 'value1', 'key2' => 'value2' }
48
+ ```
49
+
50
+ Nested hashes (through multiple `__`'s) are not yet supported.
51
+
52
+ - `Inquisitive::Environment`: **default modes**
53
+
54
+ Previously the default mode was `:dynamic`. This was mostly to prevent unexpected behaviour for newcomers.
55
+
56
+ Now `:static` is the default. This is because `Inquisitive::Environment` is meant to be loaded immediately after a boot script that prepares your environment variables, and queried often later. `:static` optimizes to this usecase.
57
+
58
+ To reproduce the old behaviour, you must explicitly pass `mode: :dynamic` each to `inquires_about` invocation. Alternatively, `mode: :lazy` might be a viable way to get the benefits of `:static` without refactoring your boot process.
59
+
60
+ ### Non-breaking
61
+
62
+ - `Inquisitive::Environment`: **cached mode now lazy mode**
63
+
64
+ The `:cached` environment mode is now known as `:lazy`. This is backwards compatible because all logic handling modes explicitly checks for `:static` or `:dynamic`, so any other named mode has the same behaviour as `:lazy`.
65
+
66
+ 1.2.0 - [2013.11.21][1.2.0]
67
+ ---------------------------
68
+
69
+ Everything to date.
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in inquisitive.gemspec
4
4
  gemspec
5
+
6
+ gem 'pry'
data/README.md CHANGED
@@ -1,15 +1,29 @@
1
1
  Inquisitive
2
2
  ===========
3
3
 
4
- Predicate methods for those curious about their datastructures.
4
+ > **Predicate methods for those curious about their datastructures.**
5
5
 
6
- Inquisitive allows you to interrogate objects about their contents with friendly, readable method chains. It's the logical conclusion of ActiveSupport's `StringInquirer`.
6
+ 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`.
7
7
 
8
- This library is extracted from several projects where I found myself building on the `Rails.env.production?` pattern: wrapping information from the `ENV` variable into more descriptive and flexible methods accessible from my main namespace. `Inquisitive::Environment` contains helper methods to further this end.
8
+ It also allows you to auto-instanciate and read inquisitive datastructures straight from your `ENV` hash through the `Inquisitive::Environment` module.
9
9
 
10
- For all intents and purposes Inquisitive has no dependencies, doesn't pollute the global constant namespace with anything but `Inquisitive`, and doesn't touch any core classes. It uses ActiveSupport's `HashWithIndifferentAccess`, but will bootstrap itself with a minimal version extracted from ActiveSupport 4.0 if it cannot be found.
10
+ 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.
11
11
 
12
- It also leans on `method_missing`, `dup`, and wrapper objects, so if your application is too inquisitive you might find it grinding to a halt. It's recommended to only use it to switch on a few core runtime environment variables. Don't serialize ActiveRecord attributes into it, is what I'm saying here.
12
+ Installation
13
+ ------------
14
+
15
+ To add to your project:
16
+
17
+ ```bash
18
+ $ echo "gem 'inquisitive'" >> Gemfile
19
+ $ bundle install
20
+ ```
21
+
22
+ Otherwise:
23
+
24
+ ```bash
25
+ gem install inquisitive
26
+ ```
13
27
 
14
28
  Usage
15
29
  -----
@@ -95,7 +109,7 @@ config.no.api?
95
109
 
96
110
  ### Inquisitive Environment
97
111
 
98
- `Inquisitive::Environment` can be used in your modules and classes to more easily interrogate the `ENV` variable:
112
+ `Inquisitive::Environment` can be used in your modules and classes to more easily interrogate `ENV` variables with inquisitive objects:
99
113
 
100
114
  #### Strings
101
115
 
@@ -134,12 +148,12 @@ MyGame.supported_databases.sql_server?
134
148
  #### Hashes
135
149
 
136
150
  ```ruby
137
- ENV['STUB_AUTHENTICATION'] = 'true'
138
- ENV['STUB_IN'] = "development"
139
- ENV['STUB_SERVICES'] = "database,api"
151
+ ENV['STUB__AUTHENTICATION'] = 'true'
152
+ ENV['STUB__IN'] = "development"
153
+ ENV['STUB__SERVICES'] = "database,api"
140
154
  class MyGame
141
155
  extend Inquisitive::Environment
142
- inquires_about 'STUB_'
156
+ inquires_about 'STUB'
143
157
  end
144
158
 
145
159
  MyGame.stub.authentication?
@@ -180,10 +194,10 @@ MyGame.env.production?
180
194
  Environment inquirers can have explicit presence checks, circumventing a common pitfall when reasoning about environment variables. Borrowing from the example above:
181
195
 
182
196
  ```ruby
183
- ENV['STUB_AUTHENTICATION'] = 'false'
197
+ ENV['STUB__AUTHENTICATION'] = 'false'
184
198
  class MyGame
185
199
  extend Inquisitive::Environment
186
- inquires_about 'STUB_'
200
+ inquires_about 'STUB'
187
201
  end
188
202
 
189
203
  MyGame.stub.authentication
@@ -220,16 +234,16 @@ MyGame.stub_registration?
220
234
 
221
235
  This only works on top-level inquirers, so there's no way to get our nested `MyGame.stubbed.authentication?` to behave as expected (currently).
222
236
 
223
- The `present_if` check uses `===` under the covers for maximum expressiveness, so you can also use it to match against regexs and other constructs.
237
+ The `present_if` check uses `===` under the covers for maximum expressiveness, so you can also use it to match against regexs, classes, and other constructs.
224
238
 
225
239
  #### Inquiry mode
226
240
 
227
- Environment inquirers have three configurable modes, defaulting to `:dynamic`:
241
+ Environment inquirers have three configurable modes, defaulting to `:static`.
228
242
 
229
243
  ```ruby
230
244
  class MyGame
231
245
  extend Inquisitive::Environment
232
- inquires_about 'STUB_', mode: %i[dynamic cached static].sample
246
+ inquires_about 'STUB', mode: %i[dynamic lazy static].sample
233
247
  end
234
248
  ```
235
249
 
@@ -239,7 +253,7 @@ end
239
253
 
240
254
  Use if you're manipulating the environment in between invocations, so `Inquisitive` can pick up on new values, detect changes between string or array notation, and discover new keys for hash notation.
241
255
 
242
- - **Cached**
256
+ - **Lazy**
243
257
 
244
258
  Environment inquiries check `ENV` on their first invocation, and re-use the response in future invocations.
245
259
 
data/Rakefile CHANGED
@@ -6,3 +6,7 @@ Rake::TestTask.new do |t|
6
6
  t.test_files = Dir['test/**/*_test.rb']
7
7
  end
8
8
  task default: :test
9
+
10
+ task :console do
11
+ `pry -I lib -r inquisitive.rb`
12
+ end
@@ -4,11 +4,20 @@ $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 = "1.2.0"
7
+ spec.version = "2.0.0"
8
8
  spec.authors = ["Chris Keele"]
9
9
  spec.email = ["dev@chriskeele.com"]
10
- spec.description = "Predicate methods for those curious about their datastructures."
11
10
  spec.summary = "Predicate methods for those curious about their datastructures."
11
+ spec.description = <<-DESC
12
+ Predicate methods for those curious about their datastructures.
13
+
14
+ Provides String, Array, and Hash subclasses with dynamic predicate methods that
15
+ allow you to interrogate the contents of the most common Ruby datastructures
16
+ in a readable, friendly fashion.
17
+
18
+ Also allows you to auto-instanciate and read inquisitive datastructures straight
19
+ from your `ENV` hash.
20
+ DESC
12
21
  spec.homepage = "https://github.com/rawsugar/inquisitive"
13
22
  spec.license = "MIT"
14
23
 
@@ -8,7 +8,7 @@ module Inquisitive
8
8
  @__env_accessors__ ||= HashWithIndifferentAccess.new
9
9
  @__env_accessors__[env_accessor] = env_var
10
10
 
11
- mode = Inquisitive[ opts.fetch(:mode, :dynamic).to_s ]
11
+ mode = Inquisitive[ opts.fetch(:mode, :static).to_s ]
12
12
 
13
13
  if mode.dynamic?
14
14
 
@@ -45,23 +45,25 @@ module Inquisitive
45
45
  end
46
46
  end
47
47
 
48
+ private
49
+
48
50
  module Parser
49
51
  class << self
50
52
 
51
53
  def [](var_name)
52
54
  if ENV.has_key? var_name
55
+
53
56
  env_var = ENV[var_name]
54
-
55
57
  if env_var.include? ','
56
58
  env_var.split(',').map(&:strip)
57
59
  else
58
60
  env_var
59
61
  end
60
62
 
61
- elsif hash_var? var_name
63
+ elsif env_vars = can_find_env_keys_from(var_name)
62
64
 
63
- Parser.env_keys_from(var_name).reduce({}) do |hash, key|
64
- hash[Parser.key_for(key, var_name)] = Inquisitive[Parser[key]]
65
+ env_vars.reduce({}) do |hash, key|
66
+ hash[key_for(key, var_name)] = Inquisitive[Parser[key]]
65
67
  hash
66
68
  end
67
69
 
@@ -69,19 +71,20 @@ module Inquisitive
69
71
  ""
70
72
  end
71
73
  end
72
-
73
- def hash_var?(var_name)
74
- var_name[-1] == '_'
74
+
75
+ def can_find_env_keys_from(var_name)
76
+ found = env_keys_from(var_name)
77
+ found.empty? ? nil : found
75
78
  end
76
79
 
77
80
  def env_keys_from(var_name)
78
81
  ENV.keys.select do |key|
79
- key =~ /^#{var_name}/
82
+ key =~ /^#{var_name}__/
80
83
  end
81
84
  end
82
85
 
83
86
  def key_for(env_key, var_name)
84
- env_key.gsub("#{var_name}", '').downcase
87
+ env_key.gsub("#{var_name}__", '').downcase
85
88
  end
86
89
 
87
90
  end
@@ -40,14 +40,6 @@ module Inquisitive
40
40
  end
41
41
  end
42
42
 
43
- def steal_default_from(hash)
44
- if hash.default_proc
45
- self.default_proc = hash.default_proc
46
- else
47
- self.default = hash.default
48
- end
49
- end
50
-
51
43
  alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
52
44
  alias_method :regular_update, :update unless method_defined?(:regular_update)
53
45
 
@@ -84,6 +76,11 @@ module Inquisitive
84
76
  def fetch(key, *extras)
85
77
  super(convert_key(key), *extras)
86
78
  end
79
+
80
+ # not sure why just this one Enumerable method fails tests without override
81
+ def reject(*args, &block)
82
+ self.class[super]
83
+ end
87
84
 
88
85
  def values_at(*indices)
89
86
  indices.collect {|key| self[convert_key(key)]}
@@ -155,6 +152,14 @@ module Inquisitive
155
152
 
156
153
  protected
157
154
 
155
+ def steal_default_from(hash)
156
+ if hash.default_proc
157
+ self.default_proc = hash.default_proc
158
+ else
159
+ self.default = hash.default
160
+ end
161
+ end
162
+
158
163
  def convert_key(key)
159
164
  key.kind_of?(Symbol) ? key.to_s : key
160
165
  end
@@ -4,18 +4,18 @@ class InquisitiveCombinatorialEnvironmentTest < EnvironmentTest
4
4
  super
5
5
  ENV['STRING'] = @raw_string
6
6
  ENV['ARRAY'] = @raw_array.join(',')
7
- ENV['HASH_AUTHENTICATION'] = @raw_hash[:authentication].to_s
8
- ENV['HASH_IN'] = @raw_hash[:in]
9
- ENV['HASH_DATABASES'] = @raw_hash[:databases].join(',')
7
+ ENV['HASH__AUTHENTICATION'] = @raw_hash[:authentication].to_s
8
+ ENV['HASH__IN'] = @raw_hash[:in]
9
+ ENV['HASH__DATABASES'] = @raw_hash[:databases].join(',')
10
10
  end
11
11
  def teardown
12
12
  super
13
13
  ENV.delete 'STRING'
14
14
  ENV.delete 'ARRAY'
15
- ENV.delete 'HASH_AUTHENTICATION'
16
- ENV.delete 'HASH_IN'
17
- ENV.delete 'HASH_DATABASES'
18
- ENV.delete 'HASH_SOMETHING_NEW'
15
+ ENV.delete 'HASH__AUTHENTICATION'
16
+ ENV.delete 'HASH__IN'
17
+ ENV.delete 'HASH__DATABASES'
18
+ ENV.delete 'HASH__SOMETHING_NEW'
19
19
  end
20
20
 
21
21
  def change_string_variable
@@ -25,12 +25,12 @@ class InquisitiveCombinatorialEnvironmentTest < EnvironmentTest
25
25
  ENV['ARRAY'] = [ ENV['ARRAY'], 'something_new' ].join ','
26
26
  end
27
27
  def change_hash_variable
28
- ENV['HASH_SOMETHING_NEW'] = 'true'
28
+ ENV['HASH__SOMETHING_NEW'] = 'true'
29
29
  end
30
30
 
31
31
  end
32
32
 
33
- %w[dynamic cached static].each do |mode|
33
+ %w[dynamic lazy static].each do |mode|
34
34
  %w[string array hash].each do |type|
35
35
 
36
36
  Inquisitive.const_set(
@@ -45,7 +45,7 @@ end
45
45
  super
46
46
  @mode = Inquisitive[self.class.mode]
47
47
  @type = Inquisitive[self.class.type]
48
- App.inquires_about @type.upcase + (@type == "hash" ? "_" : ""), mode: @mode
48
+ App.inquires_about @type.upcase, mode: @mode
49
49
  end
50
50
 
51
51
  def string
@@ -4,32 +4,25 @@ class InquisitiveEnvironmentTest < EnvironmentTest
4
4
 
5
5
  def test_missing_variable_responses
6
6
  App.inquires_about 'DOES_NOT_EXIST', with: :exists
7
- assert_equal App.exists, ""
7
+ assert_equal "", App.exists
8
8
  end
9
9
  def test_missing_variable_predicates
10
10
  App.inquires_about 'DOES_NOT_EXIST', with: :exists
11
11
  refute App.exists?
12
12
  end
13
13
 
14
- def test_missing_hash_variable_responses
15
- App.inquires_about 'DOES_NOT_EXIST_', with: :exists
16
- assert_equal App.exists, {}
17
- end
18
- def test_missing_hash_variable_predicates
19
- App.inquires_about 'DOES_NOT_EXIST_', with: :exists
20
- refute App.exists?
21
- end
22
-
23
14
  def test_autonaming_of_inquirers
24
15
  App.inquires_about 'NAME_NOT_SPECIFIED'
25
16
  assert App.respond_to? :name_not_specified
26
17
  end
27
18
 
28
- def test_default_mode_of_dynamic
29
- App.inquires_about 'DEFAULTS_TO', with: :defaults_to
30
- App.defaults_to # Call once to ensure no caching
19
+ def test_default_mode_of_static
20
+ ENV['DEFAULTS_TO'] = 'static'
21
+ App.inquires_about 'DEFAULTS_TO'
22
+ ENV['DEFAULTS_TO'] = 'lazy'
23
+ assert App.defaults_to.static?
31
24
  ENV['DEFAULTS_TO'] = 'dynamic'
32
- assert App.defaults_to.dynamic?
25
+ assert App.defaults_to.static?
33
26
  end
34
27
 
35
28
  def test_custom_string_presence
@@ -15,7 +15,7 @@ module CombinatorialEnvironmentTests
15
15
  end
16
16
 
17
17
  def test_changing_variable_after_definition
18
- App.inquires_about @type.upcase + (@type == "hash" ? "_" : ""), mode: @mode, with: :precache
18
+ App.inquires_about @type.upcase, mode: @mode, with: :precache
19
19
  test = @mode.static? ? :assert_equal : :refute_equal
20
20
  precache = App.precache
21
21
  send :"change_#{@type}_variable"
metadata CHANGED
@@ -1,79 +1,84 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inquisitive
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Keele
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-21 00:00:00.000000000 Z
11
+ date: 2014-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '5.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: simplecov
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0.7'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.7'
69
- description: Predicate methods for those curious about their datastructures.
69
+ description: " Predicate methods for those curious about their datastructures.\n
70
+ \ \n Provides String, Array, and Hash subclasses with dynamic predicate methods
71
+ that\n allow you to interrogate the contents of the most common Ruby datastructures\n
72
+ \ in a readable, friendly fashion.\n \n Also allows you to auto-instanciate
73
+ and read inquisitive datastructures straight\n from your `ENV` hash.\n"
70
74
  email:
71
75
  - dev@chriskeele.com
72
76
  executables: []
73
77
  extensions: []
74
78
  extra_rdoc_files: []
75
79
  files:
76
- - .gitignore
80
+ - ".gitignore"
81
+ - CHANGELOG.md
77
82
  - Gemfile
78
83
  - LICENSE.md
79
84
  - README.md
@@ -107,17 +112,17 @@ require_paths:
107
112
  - lib
108
113
  required_ruby_version: !ruby/object:Gem::Requirement
109
114
  requirements:
110
- - - '>='
115
+ - - ">="
111
116
  - !ruby/object:Gem::Version
112
117
  version: '0'
113
118
  required_rubygems_version: !ruby/object:Gem::Requirement
114
119
  requirements:
115
- - - '>='
120
+ - - ">="
116
121
  - !ruby/object:Gem::Version
117
122
  version: '0'
118
123
  requirements: []
119
124
  rubyforge_project:
120
- rubygems_version: 2.0.3
125
+ rubygems_version: 2.2.2
121
126
  signing_key:
122
127
  specification_version: 4
123
128
  summary: Predicate methods for those curious about their datastructures.
@@ -134,3 +139,4 @@ test_files:
134
139
  - test/shared/hash_tests.rb
135
140
  - test/shared/string_tests.rb
136
141
  - test/test_helper.rb
142
+ has_rdoc: