Class: Docscribe::Config

Inherits:
Object
  • Object
show all
Defined in:
lib/docscribe/config.rb,
lib/docscribe/config/rbs.rb,
lib/docscribe/config/emit.rb,
lib/docscribe/config/utils.rb,
lib/docscribe/config/loader.rb,
lib/docscribe/config/plugin.rb,
lib/docscribe/config/sorbet.rb,
lib/docscribe/config/sorting.rb,
lib/docscribe/config/defaults.rb,
lib/docscribe/config/template.rb,
lib/docscribe/config/filtering.rb

Overview

File and method include/exclude filtering.

Constant Summary collapse

DEFAULT =

Default configuration values used when no docscribe.yml is present or when specific keys are missing from user config.

These defaults define:

  • which documentation tags are emitted
  • default generated text
  • type inference behavior
  • method / file filtering
  • optional RBS integration
  • optional Sorbet integration
{
  'emit' => {
    'header' => false,
    'include_default_message' => true,
    'include_param_documentation' => true,
    'param_tags' => true,
    'return_tag' => true,
    'visibility_tags' => true,
    'raise_tags' => true,
    'rescue_conditional_returns' => true,
    'attributes' => false
  },
  'doc' => {
    'default_message' => 'Method documentation.',
    'param_tag_style' => 'type_name',
    'param_documentation' => 'Param documentation.',
    'sort_tags' => true,
    'tag_order' => %w[todo note api private protected param option yieldparam raise return]
  },
  'methods' => {
    'instance' => {
      'public' => {}, #: Hash[String, untyped]
      'protected' => {}, #: Hash[String, untyped]
      'private' => {} #: Hash[String, untyped]
    },
    'class' => {
      'public' => {}, #: Hash[String, untyped]
      'protected' => {}, #: Hash[String, untyped]
      'private' => {} #: Hash[String, untyped]
    }
  },
  'inference' => {
    'fallback_type' => 'Object',
    'nil_as_optional' => true,
    'treat_options_keyword_as_hash' => true
  },
  'filter' => {
    'visibilities' => %w[public protected private],
    'scopes' => %w[instance class],
    'include' => [], #: Array[String]
    'exclude' => [], #: Array[String]
    'files' => {
      'include' => [], #: Array[String]
      'exclude' => ['spec']
    }
  },
  'rbs' => {
    'enabled' => false,
    'collection' => false,
    'sig_dirs' => ['sig'],
    'collection_dirs' => [], #: Array[String]
    'collapse_generics' => false,
    'warn_missing_collection' => true,
    'collapse_object_generics' => false
  },
  'sorbet' => {
    'enabled' => false,
    'rbi_dirs' => ['sorbet/rbi', 'rbi'],
    'collapse_generics' => false,
    'collapse_object_generics' => false
  },
  'keep_descriptions' => false,
  'skip_anonymous_block_params' => false,
  'plugins' => {
    'require' => [] #: Array[String]
  }
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_path: nil, **raw) ⇒ void

Create a configuration object from a raw config hash.

Missing keys are filled from DEFAULT via deep merge.

Parameters:

  • config_path (String?) (defaults to: nil)

    optional path to the config file

  • raw (Hash<String, Object>)

    user-provided config hash



25
26
27
28
# File 'lib/docscribe/config.rb', line 25

def initialize(config_path: nil, **raw)
  @raw = deep_merge(DEFAULT, raw)
  @config_path = config_path
end

Instance Attribute Details

#config_pathObject (readonly)

Returns the value of attribute config_path.



16
17
18
# File 'lib/docscribe/config.rb', line 16

def config_path
  @config_path
end

#rawObject (readonly)

Returns the value of attribute raw.



12
13
14
# File 'lib/docscribe/config.rb', line 12

def raw
  @raw
end

Class Method Details

.default_yamlString

Return the default YAML template used by docscribe init.

The template documents the most common CLI workflows and all supported configuration sections with comments.

Returns:

  • (String)


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/docscribe/config/template.rb', line 12

def self.default_yaml
  <<~YAML
    ---
    # Docscribe configuration file
    #
    # Docscribe works without this file — create it only for customization.
    #
    # Quick start:
    #   bundle exec docscribe lib          # check what would change
    #   bundle exec docscribe -a lib       # apply safe updates
    #   bundle exec docscribe -A lib       # rebuild all doc blocks
    #   bundle exec docscribe -AkB lib     # rebuild, keep descriptions, no boilerplate

    emit:
      # What to include in generated documentation
      header: false                       # +MyClass#foo+ -> ReturnType
      param_tags: true                    # @param tags
      return_tag: true                    # @return tag
      visibility_tags: true               # @private / @protected
      raise_tags: true                    # @raise tags
      rescue_conditional_returns: true    # @return [Type] if Error
      attributes: false                   # @!attribute for attr_*

      # Placeholder text for generated docs
      include_default_message: true       # "Method documentation."
      include_param_documentation: true   # "Param documentation."

    doc:
      # Default text and formatting
      default_message: "Method documentation."
      param_documentation: "Param documentation."
      param_tag_style: "type_name"        # "type_name" or "name_type"
      sort_tags: true
      tag_order: ["todo", "note", "api", "private", "protected", "param", "option", "yieldparam", "raise", "return"]

    inference:
      # Type inference behavior
      fallback_type: "Object"             # when uncertain
      nil_as_optional: true               # String | nil => String?
      treat_options_keyword_as_hash: true # options: keyword => Hash

    filter:
      # Which methods and files to process
      # Method format: "Container#method" (instance) or "Container.method" (class)
      # Supports globs ("*#initialize") and regex ("/^MyApp::.*$/")
      include: []
      exclude: []
      visibilities: ["public", "protected", "private"]
      scopes: ["instance", "class"]

      files:
        # File paths relative to project root (globs or /regex/)
        include: []
        exclude: ["spec"]

    methods:
      # Override defaults per scope and visibility.
      # Empty {} means "use values from `doc` section".
      #
      # Example:
      #   instance:
      #     public:
      #       default_message: "Public API."
      #     private:
      #       return_tag: false
      instance:
        public: {}
        protected: {}
        private: {}
      class:
        public: {}
        protected: {}
        private: {}

    rbs:
      # Use RBS signatures for better types (requires `gem "rbs"`)
      enabled: false
      sig_dirs: ["sig"]
      collection_dirs: []                 # auto-discovered from --rbs-collection
      collapse_generics: false            # Hash<Symbol, String> => Hash
      collapse_object_generics: false     # Hash<Object, Object> => Hash (keep if inner types are useful)
      collection: false                   # auto-discover from rbs_collection.lock.yaml
      warn_missing_collection: true       # warn if rbs_collection.lock.yaml exists without --rbs-collection

    sorbet:
      # Use Sorbet inline sigs and RBI files for better types
      enabled: false
      rbi_dirs: ["sorbet/rbi", "rbi"]
      collapse_generics: false
      collapse_object_generics: false

    # Preserve existing @param/@return descriptions in aggressive mode
    keep_descriptions: false

    # Skip @param for anonymous block arguments (&) (Ruby 3.2+)
    skip_anonymous_block_params: false

    plugins:
      # Load custom plugins
      # Example:
      #   require:
      #     - ./docscribe_plugins
      #     - docscribe-rails-associations
      require: []
  YAML
end

.load(path = nil) ⇒ Docscribe::Config

Load Docscribe configuration from YAML.

Resolution order:

  • explicit path, if it exists
  • docscribe.yml in the current directory, if present
  • otherwise defaults only

Parameters:

  • path (String?) (defaults to: nil)

    optional config path

Returns:



15
16
17
18
19
20
21
# File 'lib/docscribe/config/loader.rb', line 15

def self.load(path = nil)
  raw = {} #: Hash[String, untyped]
  resolved = path if path && File.file?(path)
  resolved ||= 'docscribe.yml' if File.file?('docscribe.yml')
  raw = safe_load_file_compat(resolved) if resolved
  new(config_path: resolved, **raw) # steep:ignore
end

.safe_load_compat(yaml, filename: nil) ⇒ Hash<String, Object>, Object

Safely load YAML from a string across Psych API versions.

Parameters:

  • yaml (String)

    YAML document

  • filename (String?) (defaults to: nil)

    optional filename for diagnostics

Returns:

  • (Hash<String, Object>)
  • (Object)

    if ArgumentError

Raises:

  • (ArgumentError)


50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/docscribe/config/loader.rb', line 50

def self.safe_load_compat(yaml, filename: nil)
  pclasses = [] #: Array[String]
  psymbols = [] #: Array[Symbol]
  Psych.safe_load( # steep:ignore
    yaml,
    permitted_classes: pclasses, permitted_symbols: psymbols,
    aliases: true,
    filename: filename
  ) #: Hash[String, untyped]
rescue ArgumentError
  # Older Psych signature uses positional args
  Psych.safe_load(yaml, [], [], true, filename) # steep:ignore
end

.safe_load_file_compat(path) ⇒ Hash<String, Object>

Safely load YAML from a file across Ruby/Psych versions.

Uses YAML.safe_load_file when available, otherwise falls back to reading the file and calling safe_load_compat.

Parameters:

  • path (String)

    file path

Returns:

  • (Hash<String, Object>)


30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/docscribe/config/loader.rb', line 30

def self.safe_load_file_compat(path)
  if YAML.respond_to?(:safe_load_file) # steep:ignore
    pclasses = [] #: Array[String]
    psymbols = [] #: Array[Symbol]
    YAML.safe_load_file(path, # steep:ignore
                        permitted_classes: pclasses, permitted_symbols: psymbols,
                        aliases: true) || {} #: Hash[String, untyped]
  else
    yaml = File.open(path, 'r:bom|utf-8', &:read)
    safe_load_compat(yaml, filename: path) || {} #: Hash[String, untyped]
  end
end

Instance Method Details

#append_sorbet_providers(providers, source:, file:) ⇒ void

This method returns an undefined value.

Append Sorbet-based providers to the list.

Parameters:

  • providers (Array<Object>)

    provider list to populate

  • source (String)

    Ruby source being rewritten

  • file (String)

    source name for diagnostics



31
32
33
34
35
36
# File 'lib/docscribe/config/sorbet.rb', line 31

def append_sorbet_providers(providers, source:, file:)
  return unless sorbet_enabled?

  providers << sorbet_source_provider(source, file)
  providers << sorbet_rbi_provider
end

#build_provider_chain(providers) ⇒ Docscribe::Types::ProviderChain?

Build the provider chain from a non-empty list, or return nil.

Parameters:

  • providers (Array<Object>)

    provider list to chain

Returns:



61
62
63
64
65
66
67
# File 'lib/docscribe/config/sorbet.rb', line 61

def build_provider_chain(providers)
  providers = providers.compact
  return nil if providers.empty?

  require 'docscribe/types/provider_chain'
  Docscribe::Types::ProviderChain.new(*providers)
end

#core_rbs_providerDocscribe::Types::RBS::Provider?

Core rbs provider



29
30
31
32
33
# File 'lib/docscribe/config/rbs.rb', line 29

def core_rbs_provider
  return nil unless ruby_supports_rbs?

  @core_rbs_provider ||= build_core_rbs_provider
end

#default_message(scope, visibility) ⇒ String

Default text inserted into generated doc blocks, taking per-scope and per-visibility overrides into account.

Parameters:

  • scope (Symbol)

    :instance or :class

  • visibility (Symbol)

    :public, :protected, or :private

Returns:

  • (String)


71
72
73
74
75
76
77
78
79
80
# File 'lib/docscribe/config/emit.rb', line 71

def default_message(scope, visibility)
  method_override_str(
    scope,
    visibility,
    'default_message',
    default: raw.dig('doc', 'default_message') ||
             DEFAULT.dig('doc', 'default_message') ||
             'Method documentation.'
  )
end

#emit_attributes?Boolean

Whether to emit YARD @!attribute docs for attr_* macros.

Returns:

  • (Boolean)


46
47
48
# File 'lib/docscribe/config/emit.rb', line 46

def emit_attributes?
  fetch_bool(%w[emit attributes], false)
end

#emit_header?Boolean

Whether to emit method header lines such as:

# +MyClass#foo+ -> Integer

Returns:

  • (Boolean)


10
11
12
# File 'lib/docscribe/config/emit.rb', line 10

def emit_header?
  fetch_bool(%w[emit header], true)
end

#emit_param_tags?Boolean

Whether to emit @param tags.

Returns:

  • (Boolean)


17
18
19
# File 'lib/docscribe/config/emit.rb', line 17

def emit_param_tags?
  fetch_bool(%w[emit param_tags], true)
end

#emit_raise_tags?Boolean

Whether to emit inferred @raise tags.

Returns:

  • (Boolean)


31
32
33
# File 'lib/docscribe/config/emit.rb', line 31

def emit_raise_tags?
  fetch_bool(%w[emit raise_tags], true)
end

#emit_rescue_conditional_returns?Boolean

Whether to emit conditional rescue-return tags like:

# @return [String] if FooError

Returns:

  • (Boolean)


39
40
41
# File 'lib/docscribe/config/emit.rb', line 39

def emit_rescue_conditional_returns?
  fetch_bool(%w[emit rescue_conditional_returns], true)
end

#emit_return_tag?(scope, visibility) ⇒ Boolean

Whether to emit the @return tag for a method, taking per-scope and per-visibility overrides into account.

Parameters:

  • scope (Symbol)

    :instance or :class

  • visibility (Symbol)

    :public, :protected, or :private

Returns:

  • (Boolean)


56
57
58
59
60
61
62
63
# File 'lib/docscribe/config/emit.rb', line 56

def emit_return_tag?(scope, visibility)
  method_override_bool(
    scope,
    visibility,
    'return_tag',
    default: fetch_bool(%w[emit return_tag], true)
  )
end

#emit_visibility_tags?Boolean

Whether to emit visibility tags such as @private and @protected.

Returns:

  • (Boolean)


24
25
26
# File 'lib/docscribe/config/emit.rb', line 24

def emit_visibility_tags?
  fetch_bool(%w[emit visibility_tags], true)
end

#expand_directory_shorthand(pattern) ⇒ Array<String>

Expand a directory-like pattern into a recursive glob when appropriate.

Examples:

  • "spec/" => "spec/**/*"
  • "spec" => "spec/**/*" if spec exists as a directory

Parameters:

  • pattern (String)

    file pattern to expand

Returns:

  • (Array<String>)


91
92
93
94
95
96
97
98
99
100
101
# File 'lib/docscribe/config/filtering.rb', line 91

def expand_directory_shorthand(pattern)
  pat = pattern.dup

  if pat.end_with?('/')
    ["#{pat}**/*"]
  elsif !pat.match?(/[*?\[]|{/) && File.directory?(pat)
    ["#{pat}/**/*"]
  else
    [pat]
  end
end

#fallback_typeString

Fallback type used when inference cannot determine a more specific type.

Returns:

  • (String)


85
86
87
88
89
# File 'lib/docscribe/config/emit.rb', line 85

def fallback_type
  raw.dig('inference', 'fallback_type') ||
    DEFAULT.dig('inference', 'fallback_type') ||
    'Object'
end

#file_match_pattern?(pattern, path) ⇒ Boolean

Match a file path against a single configured file filter.

Supports:

  • /regex/
  • globs
  • recursive glob shorthand normalization

Parameters:

  • pattern (String)

    file filter pattern

  • path (String)

    file path to test

Returns:

  • (Boolean)


122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/docscribe/config/filtering.rb', line 122

def file_match_pattern?(pattern, path)
  if pattern.start_with?('/') && pattern.end_with?('/') && pattern.length >= 2
    return Regexp.new(pattern[1..-2]).match?(path) # steep:ignore
  end

  patterns_to_try = [pattern]
  patterns_to_try << pattern.gsub('/**/', '/') if pattern.include?('/**/')

  patterns_to_try.any? do |pat|
    File.fnmatch?(pat, path, File::FNM_EXTGLOB | File::FNM_DOTMATCH | File::FNM_PATHNAME)
  end
end

#file_matches_any?(patterns, path) ⇒ Boolean

Check whether a file path matches any configured file pattern.

Parameters:

  • patterns (Array<String>)

    file filter patterns

  • path (String)

    file path to test

Returns:

  • (Boolean)


108
109
110
# File 'lib/docscribe/config/filtering.rb', line 108

def file_matches_any?(patterns, path)
  patterns.any? { |pat| file_match_pattern?(pat, path) }
end

#filter_exclude_patternsArray<String>

Exclude method filter patterns.

Returns:

  • (Array<String>)


153
154
155
156
# File 'lib/docscribe/config/filtering.rb', line 153

def filter_exclude_patterns
  Array(raw.dig('filter', 'exclude') ||
        DEFAULT.dig('filter', 'exclude')).map(&:to_s).reject(&:empty?) # steep:ignore
end

#filter_include_patternsArray<String>

Include method filter patterns.

Returns:

  • (Array<String>)


161
162
163
164
# File 'lib/docscribe/config/filtering.rb', line 161

def filter_include_patterns
  Array(raw.dig('filter', 'include') ||
        DEFAULT.dig('filter', 'include')).map(&:to_s).reject(&:empty?) # steep:ignore
end

#filter_scopesArray<String>

Allowed method scopes from config/defaults.

Returns:

  • (Array<String>)


138
139
140
# File 'lib/docscribe/config/filtering.rb', line 138

def filter_scopes
  Array(raw.dig('filter', 'scopes') || DEFAULT.dig('filter', 'scopes')).map(&:to_s) # steep:ignore
end

#filter_visibilitiesArray<String>

Allowed method visibilities from config/defaults.

Returns:

  • (Array<String>)


145
146
147
148
# File 'lib/docscribe/config/filtering.rb', line 145

def filter_visibilities
  Array(raw.dig('filter', 'visibilities') ||
        DEFAULT.dig('filter', 'visibilities')).map(&:to_s) # steep:ignore
end

#include_default_message?Boolean

Whether to include the default placeholder line:

# Method documentation.

Returns:

  • (Boolean)


131
132
133
# File 'lib/docscribe/config/emit.rb', line 131

def include_default_message?
  fetch_bool(%w[emit include_default_message], true)
end

#include_param_documentation?Boolean

Whether to append placeholder text to generated @param tags:

# @param [String] name Param documentation.

Returns:

  • (Boolean)


139
140
141
# File 'lib/docscribe/config/emit.rb', line 139

def include_param_documentation?
  fetch_bool(%w[emit include_param_documentation], true)
end

#keep_descriptions?Boolean

Whether to preserve existing @param/@return descriptions in aggressive mode.

Returns:

  • (Boolean)


146
147
148
# File 'lib/docscribe/config/emit.rb', line 146

def keep_descriptions?
  fetch_bool(%w[keep_descriptions], false)
end

#load_file_patterns(Array<String>, Array<String>)

Load normalized file include/exclude patterns from config.

Returns:

  • ((Array<String>, Array<String>))


26
27
28
29
# File 'lib/docscribe/config/filtering.rb', line 26

def load_file_patterns
  files = raw.dig('filter', 'files') || {}
  [normalize_file_patterns(files['include']), normalize_file_patterns(files['exclude'])]
end

#load_plugins!void

This method returns an undefined value.

Load and register plugins declared under plugins.require in config.

Each entry is expanded relative to the current working directory and passed to require. Registration is expected to happen inside the required file via Plugin::Registry.register.

Loading failures are non-fatal: a warning is printed and the run continues without the plugin.

Raises:

  • (LoadError)


17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/docscribe/config/plugin.rb', line 17

def load_plugins!
  paths = Array(raw.dig('plugins', 'require')).compact #: Array[String]
  return if paths.empty?

  require 'docscribe/plugin'

  paths.each do |path|
    require File.expand_path(path)
  rescue LoadError => e
    warn "Docscribe: could not load plugin #{path.inspect}: #{e.message}"
  end
end

#nil_as_optional?Boolean

Whether unions involving nil should be rendered as optional types.

For example, String, nil may become String? depending on formatter behavior.

Returns:

  • (Boolean)


97
98
99
# File 'lib/docscribe/config/emit.rb', line 97

def nil_as_optional?
  fetch_bool(%w[inference nil_as_optional], true)
end

#normalize_file_patterns(list) ⇒ Array<String>

Normalize file filter patterns:

  • compact nils
  • stringify
  • remove empties
  • expand shorthand directory forms

Parameters:

  • list (Array<String>?)

    raw pattern list

Returns:

  • (Array<String>)


79
80
81
# File 'lib/docscribe/config/filtering.rb', line 79

def normalize_file_patterns(list)
  Array(list).compact.map(&:to_s).reject(&:empty?).flat_map { |pat| expand_directory_shorthand(pat) }.uniq
end

#param_documentationString

Default generated parameter description text.

Returns:

  • (String)


123
124
125
# File 'lib/docscribe/config/emit.rb', line 123

def param_documentation
  raw.dig('doc', 'param_documentation') || DEFAULT.dig('doc', 'param_documentation')
end

#param_tag_styleString

Param tag syntax style.

Supported values:

  • "type_name" => @param [String] name
  • "name_type" => @param name [String]

Returns:

  • (String)


116
117
118
# File 'lib/docscribe/config/emit.rb', line 116

def param_tag_style
  raw.dig('doc', 'param_tag_style') || DEFAULT.dig('doc', 'param_tag_style')
end

#process_file?(path) ⇒ Boolean

Decide whether a file path should be processed based on filter.files.

File paths are matched relative to the current working directory when possible. Exclude rules win. If no include rules are configured, files are included by default.

Parameters:

  • path (String)

    file path to test

Returns:

  • (Boolean)


13
14
15
16
17
18
19
20
21
# File 'lib/docscribe/config/filtering.rb', line 13

def process_file?(path)
  include_patterns, exclude_patterns = load_file_patterns
  rel = relative_path(path)

  return false if file_matches_any?(exclude_patterns, rel)
  return true if include_patterns.empty?

  file_matches_any?(include_patterns, rel)
end

#process_method?(container:, scope:, visibility:, name:) ⇒ Boolean

Decide whether a method should be processed based on configured method filters.

Method IDs are normalized as:

  • instance method => MyModule::MyClass#foo
  • class method => MyModule::MyClass.foo

Exclude rules win. If no include rules are configured, methods are included by default subject to scope and visibility allow-lists.

Parameters:

  • container (String)

    enclosing class/module name

  • scope (Symbol)

    :instance or :class

  • visibility (Symbol)

    :public, :protected, or :private

  • name (String, Symbol)

    method name

Returns:

  • (Boolean)


57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/docscribe/config/filtering.rb', line 57

def process_method?(container:, scope:, visibility:, name:)
  return false unless filter_scopes.include?(scope.to_s)
  return false unless filter_visibilities.include?(visibility.to_s)

  method_id = "#{container}#{scope == :instance ? '#' : '.'}#{name}"

  return false if matches_any?(filter_exclude_patterns, method_id)

  inc = filter_include_patterns
  return true if inc.empty?

  matches_any?(inc, method_id)
end

#rbs_enabled?Boolean

Whether RBS integration is enabled.

Returns:

  • (Boolean)


22
23
24
# File 'lib/docscribe/config/rbs.rb', line 22

def rbs_enabled?
  fetch_bool(%w[rbs enabled], false)
end

#rbs_providerDocscribe::Types::RBS::Provider?

Return a memoized RBS provider if RBS integration is enabled and available.

If RBS cannot be loaded, this returns nil and Docscribe falls back to inference.



12
13
14
15
16
17
# File 'lib/docscribe/config/rbs.rb', line 12

def rbs_provider
  return nil unless rbs_enabled?
  return nil unless ruby_supports_rbs?

  @rbs_provider ||= build_rbs_provider
end

#rbs_warn_missing_collection?Boolean

Whether to warn when rbs_collection.lock.yaml exists but --rbs-collection was not passed.

Set rbs.warn_missing_collection: false in docscribe.yml to suppress.

Returns:

  • (Boolean)


41
42
43
# File 'lib/docscribe/config/rbs.rb', line 41

def rbs_warn_missing_collection?
  fetch_bool(%w[rbs warn_missing_collection], true)
end

#relative_path(path) ⇒ String

Compute the relative path for filtering.

Parameters:

  • path (String)

    file path to test

Returns:

  • (String)
  • (String)

    if StandardError

Raises:

  • (StandardError)


37
38
39
40
41
# File 'lib/docscribe/config/filtering.rb', line 37

def relative_path(path)
  Pathname.new(path).expand_path.relative_path_from(Pathname.pwd).cleanpath.to_s
rescue StandardError
  path
end

#signature_provider_for(source:, file:) ⇒ Docscribe::Types::ProviderChain?

Build the effective external signature provider chain for a given source.

Provider precedence is:

  1. inline Sorbet signatures from the current source
  2. Sorbet RBI files
  3. RBS files

Returns nil when no external type provider is enabled or available.

Parameters:

  • source (String)

    Ruby source being rewritten

  • file (String)

    source name for diagnostics

Returns:



18
19
20
21
22
23
# File 'lib/docscribe/config/sorbet.rb', line 18

def signature_provider_for(source:, file:)
  providers = [] #: Array[untyped]
  append_sorbet_providers(providers, source: source, file: file)
  providers << rbs_provider if rbs_enabled?
  build_provider_chain(providers)
end

#skip_anonymous_block_params?Boolean

Whether to skip @param generation for anonymous block arguments (&).

Ruby 3.2+ allows def foo(&). When enabled, no @param is generated for anonymous block parameters since they have no name to reference.

Returns:

  • (Boolean)


156
157
158
# File 'lib/docscribe/config/emit.rb', line 156

def skip_anonymous_block_params?
  fetch_bool(%w[skip_anonymous_block_params], false)
end

#sorbet_collapse_generics?Boolean

Whether generic Sorbet/RBI container types should be simplified.

Falls back to the RBS collapse_generics setting when Sorbet-specific config is not present.

Returns:

  • (Boolean)


106
107
108
# File 'lib/docscribe/config/sorbet.rb', line 106

def sorbet_collapse_generics?
  fetch_bool(%w[sorbet collapse_generics], rbs_collapse_generics?)
end

#sorbet_collapse_object_generics?Boolean

Whether to collapse Object-typed generics in Sorbet types.

Falls back to the RBS setting when Sorbet-specific config is not present.

Returns:

  • (Boolean)


115
116
117
# File 'lib/docscribe/config/sorbet.rb', line 115

def sorbet_collapse_object_generics?
  fetch_bool(%w[sorbet collapse_object_generics], rbs_collapse_object_generics?)
end

#sorbet_enabled?Boolean

Whether Sorbet support is enabled in config.

Returns:

  • (Boolean)


89
90
91
# File 'lib/docscribe/config/sorbet.rb', line 89

def sorbet_enabled?
  fetch_bool(%w[sorbet enabled], false)
end

#sorbet_rbi_dirsArray<String>

RBI directories searched by the Sorbet provider.

Returns:

  • (Array<String>)


96
97
98
# File 'lib/docscribe/config/sorbet.rb', line 96

def sorbet_rbi_dirs
  Array(raw.dig('sorbet', 'rbi_dirs') || DEFAULT.dig('sorbet', 'rbi_dirs')).map(&:to_s) # steep:ignore
end

#sorbet_rbi_providerDocscribe::Types::Sorbet::RBIProvider?

Return a memoized Sorbet RBI provider if Sorbet integration is enabled.

Returns:

Raises:

  • (LoadError)


73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/docscribe/config/sorbet.rb', line 73

def sorbet_rbi_provider
  return nil unless sorbet_enabled?

  @sorbet_rbi_provider ||= begin
    require 'docscribe/types/sorbet/rbi_provider'
    Docscribe::Types::Sorbet::RBIProvider.new(rbi_dirs: sorbet_rbi_dirs,
                                              collapse_generics: sorbet_collapse_generics?,
                                              collapse_object_generics: sorbet_collapse_object_generics?)
  rescue LoadError
    nil
  end
end

#sorbet_source_provider(source, file) ⇒ Docscribe::Types::Sorbet::SourceProvider?

Build a Sorbet source provider (inline sigs).

Parameters:

  • source (String)

    Ruby source being rewritten

  • file (String)

    source name for diagnostics

Returns:

Raises:

  • (LoadError)


45
46
47
48
49
50
51
52
53
54
55
# File 'lib/docscribe/config/sorbet.rb', line 45

def sorbet_source_provider(source, file)
  require 'docscribe/types/sorbet/source_provider'
  Docscribe::Types::Sorbet::SourceProvider.new(
    source: source,
    file: file,
    collapse_generics: sorbet_collapse_generics?,
    collapse_object_generics: sorbet_collapse_object_generics?
  )
rescue LoadError
  nil
end

#sort_tags?Boolean

Whether sortable tag normalization is enabled for doc-like blocks.

Returns:

  • (Boolean)


9
10
11
# File 'lib/docscribe/config/sorting.rb', line 9

def sort_tags?
  raw.dig('doc', 'sort_tags') != false
end

#tag_orderArray<String>

Configured sortable tag order.

Tags are normalized without a leading @.

Returns:

  • (Array<String>)


18
19
20
21
22
# File 'lib/docscribe/config/sorting.rb', line 18

def tag_order
  Array(raw.dig('doc', 'tag_order') || DEFAULT.dig('doc', 'tag_order')).map do |t|
    t.to_s.sub(/\A@/, '') # steep:ignore
  end
end

#treat_options_keyword_as_hash?Boolean

Whether keyword arguments named options / options: should be treated specially as Hash values during inference.

Returns:

  • (Boolean)


105
106
107
# File 'lib/docscribe/config/emit.rb', line 105

def treat_options_keyword_as_hash?
  fetch_bool(%w[inference treat_options_keyword_as_hash], true)
end