|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +module Mongoid |
| 4 | + module Config |
| 5 | + |
| 6 | + # This module provides a way to inspect not only the defined configuration |
| 7 | + # settings and their defaults (which are available via |
| 8 | + # `Mongoid::Config.settings`), but also the documentation about them. It |
| 9 | + # does this by scraping the `mongoid/config.rb` file with a regular |
| 10 | + # expression to match comments with options. |
| 11 | + # |
| 12 | + # @api private |
| 13 | + module Introspection |
| 14 | + extend self |
| 15 | + |
| 16 | + # A helper class to represent an individual option, its name, its |
| 17 | + # default value, and the comment that documents it. |
| 18 | + class Option |
| 19 | + # The name of this option. |
| 20 | + # |
| 21 | + # @return [ String ] The name of the option |
| 22 | + attr_reader :name |
| 23 | + |
| 24 | + # The default value of this option. |
| 25 | + # |
| 26 | + # @return [ Object ] The default value of the option, typically a |
| 27 | + # String, Symbol, nil, true, or false. |
| 28 | + attr_reader :default |
| 29 | + |
| 30 | + # The comment that describes this option, as scraped from |
| 31 | + # mongoid/config.rb. |
| 32 | + # |
| 33 | + # @return [ String ] The (possibly multi-line) comment. Each line is |
| 34 | + # prefixed with the Ruby comment character ("#"). |
| 35 | + attr_reader :comment |
| 36 | + |
| 37 | + # Instantiate an option from an array of Regex captures. |
| 38 | + # |
| 39 | + # @param [ Array<String> ] captures The array with the Regex captures |
| 40 | + # to use to instantiate the option. The element at index 1 must be |
| 41 | + # the comment, at index 2 must be the name, and at index 3 must be |
| 42 | + # the default value. |
| 43 | + # |
| 44 | + # @return [ Option ] The newly instantiated Option object. |
| 45 | + def self.from_captures(captures) |
| 46 | + new(captures[2], captures[3], captures[1]) |
| 47 | + end |
| 48 | + |
| 49 | + # Create a new Option instance with the given name, default value, |
| 50 | + # and comment. |
| 51 | + # |
| 52 | + # @param [ String ] name The option's name. |
| 53 | + # @param [ String ] default The option's default value, as a String |
| 54 | + # representing the actual Ruby value. |
| 55 | + # @param [ String ] comment The multi-line comment describing the |
| 56 | + # option. |
| 57 | + def initialize(name, default, comment) |
| 58 | + @name, @default, @comment = name, default, unindent(comment) |
| 59 | + end |
| 60 | + |
| 61 | + # Indent the comment by the requested amount, optionally indenting the |
| 62 | + # first line, as well. |
| 63 | + # |
| 64 | + # param [ Integer ] indent The number of spaces to indent each line |
| 65 | + # (Default: 2) |
| 66 | + # param [ true | false ] indent_first_line Whether or not to indent |
| 67 | + # the first line of the comment (Default: false) |
| 68 | + # |
| 69 | + # @return [ String ] the reformatted comment |
| 70 | + def indented_comment(indent: 2, indent_first_line: false) |
| 71 | + comment.gsub(/^/, " " * indent).tap do |result| |
| 72 | + result.strip! unless indent_first_line |
| 73 | + end |
| 74 | + end |
| 75 | + |
| 76 | + # Reports whether or not the text "(Deprecated)" is present in the |
| 77 | + # option's comment. |
| 78 | + # |
| 79 | + # @return [ true | false ] whether the option is deprecated or not. |
| 80 | + def deprecated? |
| 81 | + comment.include?("(Deprecated)") |
| 82 | + end |
| 83 | + |
| 84 | + # Compare self with the given option. |
| 85 | + # |
| 86 | + # @return [ true | false ] If name, default, and comment are all the |
| 87 | + # same, return true. Otherwise, false. |
| 88 | + def ==(option) |
| 89 | + name == option.name && |
| 90 | + default == option.default && |
| 91 | + comment == option.comment |
| 92 | + end |
| 93 | + |
| 94 | + private |
| 95 | + |
| 96 | + # Removes any existing whitespace from the beginning of each line in |
| 97 | + # the text. |
| 98 | + # |
| 99 | + # @param [ String ] text The text to unindent. |
| 100 | + # |
| 101 | + # @return [ String ] the unindented text. |
| 102 | + def unindent(text) |
| 103 | + text.strip.gsub(/^\s+/, "") |
| 104 | + end |
| 105 | + end |
| 106 | + |
| 107 | + # A regular expression that looks for option declarations of the format: |
| 108 | + # |
| 109 | + # # one or more lines of comments, |
| 110 | + # # followed immediately by an option |
| 111 | + # # declaration with a default value: |
| 112 | + # option :option_name, default: "something" |
| 113 | + # |
| 114 | + # The regex produces three captures: |
| 115 | + # |
| 116 | + # 1: the (potentially multiline) comment |
| 117 | + # 2: the option's name |
| 118 | + # 3: the option's default value |
| 119 | + OPTION_PATTERN = %r{ |
| 120 | + ( |
| 121 | + ((?:^\s*\#.*\n)+) # match one or more lines of comments |
| 122 | + ^\s+option\s+ # followed immediately by a line declaring an option |
| 123 | + :(\w+),\s+ # match the option's name, followed by a comma |
| 124 | + default:\s+(.*) # match the default value for the option |
| 125 | + \n) # end with a newline |
| 126 | + }x |
| 127 | + |
| 128 | + # The full path to the source file of the Mongoid::Config module. |
| 129 | + CONFIG_RB_PATH = File.absolute_path(File.join( |
| 130 | + File.dirname(__FILE__), "../config.rb")) |
| 131 | + |
| 132 | + # Extracts the available configuration options from the Mongoid::Config |
| 133 | + # source file, and returns them as an array of hashes. |
| 134 | + # |
| 135 | + # @param [ true | false ] include_deprecated Whether deprecated options |
| 136 | + # should be included in the list. (Default: false) |
| 137 | + # |
| 138 | + # @return [ Array<Introspection::Option>> ] the array of option objects |
| 139 | + # representing each defined option, in alphabetical order by name. |
| 140 | + def options(include_deprecated: false) |
| 141 | + src = File.read(CONFIG_RB_PATH) |
| 142 | + src.scan(OPTION_PATTERN) |
| 143 | + .map { |opt| Option.from_captures(opt) } |
| 144 | + .reject { |opt| !include_deprecated && opt.deprecated? } |
| 145 | + .sort_by { |opt| opt.name } |
| 146 | + end |
| 147 | + end |
| 148 | + |
| 149 | + end |
| 150 | +end |
0 commit comments