diff options
31 files changed, 571 insertions, 851 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e7c238ac..d259460c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ * Added ability to forward ARGV to a Pry session via `--` (or `-`) when launching Pry from shell ([#1902](https://github.com/pry/pry/commit/5cd65d3c0eb053f6edcdf571eea5d0cd990626ed)) +* Added `Pry::Config::LazyValue` & `Pry::Config::MemoizedValue`, which allow + storing callable procs in the config + ([#2024](https://github.com/pry/pry/pull/2024)) #### API changes @@ -65,6 +68,8 @@ ([#2001](https://github.com/pry/pry/pull/2001)) * Deleted `Pry::BlockCommand#opts` (use `#context` instead) ([#2003](https://github.com/pry/pry/pull/2003)) +* Deleted `Pry.lazy` (use `Pry::Config::LazyValue` instead) + ([#2024](https://github.com/pry/pry/pull/2024)) #### Bug fixes @@ -45,9 +45,10 @@ require 'pry/commands/ls/ls_entity' require 'pry/commands/ls/methods_helper' require 'pry/commands/ls' -require 'pry/config/convenience' -require 'pry/config/lazy' -require 'pry/config/behavior' +require 'pry/config/attributable' +require 'pry/config/value' +require 'pry/config/memoized_value' +require 'pry/config/lazy_value' require 'pry/config' require 'pry/pry_class' diff --git a/lib/pry/commands/ls/formatter.rb b/lib/pry/commands/ls/formatter.rb index 147e86ec..8b0ae6b6 100644 --- a/lib/pry/commands/ls/formatter.rb +++ b/lib/pry/commands/ls/formatter.rb @@ -20,7 +20,7 @@ class Pry private def color(type, str) - Pry::Helpers::Text.send pry_instance.config.ls["#{type}_color"], str + Pry::Helpers::Text.send pry_instance.config.ls.send("#{type}_color"), str end # Add a new section to the output. diff --git a/lib/pry/config.rb b/lib/pry/config.rb index 194535cc..dea97447 100644 --- a/lib/pry/config.rb +++ b/lib/pry/config.rb @@ -1,37 +1,180 @@ +require 'ostruct' + class Pry - # The Pry config. - # @api public - class Config < Pry::BasicObject - include Behavior - - # @return [Pry::Config] - # An object who implements the default configuration for all - # Pry sessions. - def self.defaults - defaults = from_hash( - input: Pry.lazy { lazy_readline(defaults) }, + # @api private + class Config + extend Attributable + + # @return [IO, #readline] he object from which Pry retrieves its lines of + # input + attribute :input + + # @return [IO, #puts] where Pry should output results provided by {input} + attribute :output + + # @return [Pry::CommandSet] + attribute :commands + + # @return [Proc] the printer for Ruby expressions (not commands) + attribute :print + + # @return [Proc] the printer for exceptions + attribute :exception_handler + + # @return [Array] Exception that Pry shouldn't rescue + attribute :unrescued_exceptions + + # @deprecated + # @return [Array] Exception that Pry shouldn't rescue + attribute :exception_whitelist + + # @return [Integer] The number of lines of context to show before and after + # exceptions + attribute :default_window_size + + # @return [Pry::Hooks] + attribute :hooks + + # @return [Pry::Prompt] + attribute :prompt + + # @return [String] The display name that is part of the prompt + attribute :prompt_name + + # @return [Array<Object>] the list of objects that are known to have a + # 1-line #inspect output suitable for prompt + attribute :prompt_safe_contexts + + # If it is a String, then that String is used as the shell + # command to invoke the editor. + # + # If it responds to #call is callable then `file`, `line`, and `reloading` + # are passed to it. `reloading` indicates whether Pry will be reloading code + # after the shell command returns. All parameters are optional. + # @return [String, #call] + attribute :editor + + # A string that must precede all commands. For example, if is is + # set to "%", the "cd" command must be invoked as "%cd"). + # @return [String] + attribute :command_prefix + + # @return [Boolean] + attribute :color + + # @return [Boolean] + attribute :pager + + # @return [Boolean] whether the global ~/.pryrc should be loaded + attribute :should_load_rc + + # @return [Boolean] whether the local ./.pryrc should be loaded + attribute :should_load_local_rc + + # @return [Boolean] + attribute :should_load_plugins + + # @return [Boolean] whether to load files specified with the -r flag + attribute :should_load_requires + + # @return [Boolean] whether to disable edit-method's auto-reloading behavior + attribute :disable_auto_reload + + # Whether Pry should trap SIGINT and cause it to raise an Interrupt + # exception. This is only useful on JRuby, MRI does this for us. + # @return [Boolean] + attribute :should_trap_interrupts + + # @return [Pry::History] + attribute :history + + # @return [Boolean] + attribute :history_save + + # @return [Boolean] + attribute :history_load + + # @return [String] + attribute :history_file + + # @return [Array<String,Regexp>] + attribute :history_ignorelist + + # @return [Array<String>] Ruby files to be required + attribute :requires + + # @return [Integer] how many input/output lines to keep in memory + attribute :memory_size + + # @return [Proc] + attribute :control_d_handler + + # @return [Proc] The proc that runs system commands + attribute :system + + # @return [Boolean] + attribute :auto_indent + + # @return [Boolean] + attribute :correct_indent + + # @return [Boolean] whether or not display a warning when a command name + # collides with a method/local in the current context. + attribute :collision_warning + + # @return [Hash{Symbol=>Proc}] + attribute :extra_sticky_locals + + # @return [#build_completion_proc] a completer to use + attribute :completer + + # @return [Boolean] suppresses whereami output on `binding.pry` + attribute :quiet + + # @return [Boolean] displays a warning about experience improvement on + # Windows + attribute :windows_console_warning + + # @return [Proc] + attribute :command_completions + + # @return [Proc] + attribute :file_completions + + # @return [Hash] + attribute :ls + + # @return [String] a line of code to execute in context before the session + # starts + attribute :exec_string + + # @return [String] + attribute :output_prefix + + def initialize + merge!( + input: MemoizedValue.new { lazy_readline }, output: $stdout.tap { |out| out.sync = true }, commands: Pry::Commands, - prompt_name: Pry::Prompt::DEFAULT_NAME, + prompt_name: 'pry', prompt: Pry::Prompt[:default], - prompt_safe_contexts: Pry::Prompt::SAFE_CONTEXTS, + prompt_safe_contexts: [String, Numeric, Symbol, nil, true, false], print: Pry::ColorPrinter.method(:default), quiet: false, exception_handler: Pry::ExceptionHandler.method(:handle_exception), + unrescued_exceptions: [ ::SystemExit, ::SignalException, Pry::TooSafeException ], - exception_whitelist: Pry.lazy do - defaults.output.puts( + exception_whitelist: MemoizedValue.new do + output.puts( '[warning] Pry.config.exception_whitelist is deprecated, ' \ 'please use Pry.config.unrescued_exceptions instead.' ) - [::SystemExit, ::SignalException, Pry::TooSafeException] + unrescued_exceptions end, - # The default hooks - display messages when beginning and ending Pry - # sessions. hooks: Pry::Hooks.default, pager: true, system: Pry::SystemCommandHandler.method(:default), @@ -42,11 +185,11 @@ class Pry should_load_local_rc: true, should_trap_interrupts: Pry::Helpers::Platform.jruby?, disable_auto_reload: false, - command_prefix: "", + command_prefix: '', auto_indent: Pry::Helpers::BaseHelpers.use_ansi_codes?, correct_indent: true, collision_warning: false, - output_prefix: "=> ", + output_prefix: '=> ', requires: [], should_load_requires: true, should_load_plugins: true, @@ -54,29 +197,72 @@ class Pry control_d_handler: Pry::ControlDHandler.method(:default), memory_size: 100, extra_sticky_locals: {}, - command_completions: proc { defaults.commands.keys }, - file_completions: proc { Dir["."] }, - ls: Pry::Config.from_hash(Pry::Command::Ls::DEFAULT_OPTIONS), + command_completions: proc { commands.keys }, + file_completions: proc { Dir['.'] }, + ls: OpenStruct.new(Pry::Command::Ls::DEFAULT_OPTIONS), completer: Pry::InputCompleter, - history: { - should_save: true, - should_load: true, - file: Pry::History.default_file - }, - exec_string: "" + history_save: true, + history_load: true, + history_file: Pry::History.default_file, + history_ignorelist: [], + history: MemoizedValue.new do + if defined?(input::HISTORY) + Pry::History.new(history: input::HISTORY) + else + Pry::History.new + end + end, + exec_string: '' ) + + @custom_attrs = {} + end + + def merge!(config_hash) + config_hash.each_pair { |attr, value| __send__("#{attr}=", value) } + self + end + + def merge(config_hash) + dup.merge!(config_hash) + end + + def []=(attr, value) + @custom_attrs[attr.to_s] = Config::Value.new(value) end - def self.shortcuts - Convenience::SHORTCUTS + def [](attr) + @custom_attrs[attr.to_s].call end - # @api private - def self.lazy_readline(defaults) + def method_missing(method_name, *args, &block) + name = method_name.to_s + + if name.end_with?('=') + self[name[0..-2]] = args.first + elsif @custom_attrs.key?(name) + self[name] + else + super + end + end + + def respond_to_missing?(method_name, include_all = false) + @custom_attrs.key?(method_name.to_s.tr('=', '')) || super + end + + def initialize_dup(other) + super + @custom_attrs = @custom_attrs.dup + end + + private + + def lazy_readline require 'readline' ::Readline rescue LoadError - defaults.output.puts( + output.puts( "Sorry, you can't use Pry without Readline or a compatible library. \n" \ "Possible solutions: \n" \ " * Rebuild Ruby with Readline support using `--with-readline` \n" \ @@ -85,6 +271,5 @@ class Pry ) raise end - private_class_method :lazy_readline end end diff --git a/lib/pry/config/attributable.rb b/lib/pry/config/attributable.rb new file mode 100644 index 00000000..4ff4e7cb --- /dev/null +++ b/lib/pry/config/attributable.rb @@ -0,0 +1,20 @@ +class Pry + class Config + # Attributable provides the ability to create "attribute" + # accessors. Attribute accessors create a standard "attr_writer" and a + # customised "attr_reader". This reader is Proc-aware (lazy). + # + # @since ?.?.? + # @api private + module Attributable + def attribute(attr_name) + define_method(attr_name) do + value = Config::Value.new(instance_variable_get("@#{attr_name}")) + value.call + end + + attr_writer(attr_name) + end + end + end +end diff --git a/lib/pry/config/behavior.rb b/lib/pry/config/behavior.rb deleted file mode 100644 index 1fb51f99..00000000 --- a/lib/pry/config/behavior.rb +++ /dev/null @@ -1,377 +0,0 @@ -class Pry - class Config < Pry::BasicObject - # - # {Pry::Config::Behavior} is a module who can be included by classes who - # wish to behave similar to an OpenStruct object: - # - # ```ruby - # class Store - # include Pry::Config::Behavior - # end - # store = Store.from_hash(number: 300) - # store.number # => 300 - # store[:number] # => 300 - # store['number'] # => 300 - # ``` - # - # Classes who include {Pry::Config::Behavior} can be linked to each other - # to provide a default in case a key does not exist locally: - # - # ```ruby - # class Store - # include Pry::Config::Behavior - # end - # store = Store.from_hash({}, Store.from_hash(greeting: 'hello')) - # store.greeting # => 'hello' - # ``` - # - # When an object is read from a default like in the example above, a copy - # of the object is created to avoid a mutation changing its value: - # - # ```ruby - # default = Store.from_hash(greeting: 'hello') - # store = Store.from_hash({}, default) - # store.greeting # => 'hello' - # default.greeting.sub! 'hello', 'goodbye' - # store.greeting # => 'hello' - # ``` - # - module Behavior - ASSIGNMENT = "=".freeze - - NODUP = [ - TrueClass, FalseClass, NilClass, Symbol, Numeric, Module, Proc, Method, - Pry::Prompt, Pry::Config::Lazy - ].freeze - - INSPECT_REGEXP = /#{Regexp.escape "default=#<"}/.freeze - ReservedKeyError = Class.new(RuntimeError) - - # - # The instance methods of this module are available as singleton methods - # on classes who include {Pry::Config::Behavior}. The methods can be used - # to initialize a {Pry::Config::Behavior} object from a Hash object. - # - # @example - # class Store - # include Pry::Config::Behavior - # end - # obj1 = Store.assign(foo: 1, bar: 2) - # obj2 = Store.from_hash(foo: 1, bar: 2) - # [obj1.class, obj2.class] # => [Store, Store] - # - module Builder - # - # @example - # c = Pry::Config.assign(foo: {bar: {baz: 42}}) - # c.class # => Pry::Config - # c.foo.class # => Hash - # - # @param - # (see #from_hash) - # - # @return [Pry::Config::Behavior] - # An instance of an object that has included Pry::Config::Behavior. - # `attributes` is not visited using recursion. - # - def assign(attributes, default = nil) - new(default).tap do |behavior| - behavior.merge!(attributes) - end - end - - # - # @example - # c = Pry::Config.from_hash(foo: {bar: {baz: 42}}) - # c.foo.bar.class # => Pry::Config - # c.foo.bar.baz # => 42 - # - # @param [Hash] attributes - # - # @param [Pry::Config::Behavior, nil] default - # A default, or nil for none. - # - # @return [Pry::Config::Behavior] - # An instance of an object that has included Pry::Config::Behavior. - # `attributes` is visited using recursion. - # - def from_hash(attributes, default = nil) - new(default).tap do |config| - attributes.each do |key, value| - config[key] = if value.is_a?(Hash) - from_hash(value) - elsif value.is_a?(Array) - value.map { |v| v.is_a?(Hash) ? from_hash(v) : v } - else - value - end - end - end - end - end - - def self.included(klass) - klass.extend(Builder) - end - - # - # @example - # class Store - # include Pry::Config::Behavior - # end - # c = Store.new(Pry.config) - # c.input # => Readline - # - # @param [Pry::Config::Behavior, nil] default - # A default to query when a key is not found in self, or nil for none. - # - # - def initialize(default = Pry.config) - @default = default - @lookup = {} - @reserved_keys = methods.map(&:to_s).freeze - end - - # - # @return [Pry::Config::Behavior, nil] - # The object queried when a key is not found in self. - # - def default - @default - end - - # - # @param [#to_s] key - # - # @return [Object, BasicObject] - # An object - # - def [](key) - key = key.to_s - obj = key?(key) ? @lookup[key] : (@default && @default[key]) - obj.is_a?(Pry::Config::Lazy) ? obj.call : obj - end - - # - # Assigns a key/value pair. - # - # @param [#to_s] key - # - # @param [Object, BasicObject] value - # - # @raise [Pry::Config::ReservedKeyError] - # When `key` is a reserved key. - # - def []=(key, value) - key = key.to_s - if @reserved_keys.include?(key) - raise ReservedKeyError, - "It is not possible to use '#{key}' as a key name, please " \ - "choose a different key name." - end - - __push(key, value) - end - - # - # Removes `key` from self and allows the next lookup for `key` to - # traverse back to {#default}. - # - # @example - # pry_instance.config.prompt_name = 'foo' - # pry_instance.config.forget(:prompt_name) - # pry_instance.config.prompt_name # => 'pry' - # - # @param [#to_s] key - # - # @return [void] - # - def forget(key) - key = key.to_s - __remove(key) - default.forget(key) if default && default != last_default - end - - # - # @example - # c = Pry::Config.from_hash(foo: 1) - # c.merge!(bar: 2) - # c.merge!(Pry::Config.from_hash(baz: 3)) - # - # @param [Hash, #to_h, #to_hash] other - # An object to merge into self. - # - # @return [void] - # - def merge!(other) - other = __try_convert_to_hash(other) - raise TypeError, "unable to convert argument into a Hash" unless other - - other.each do |key, value| - self[key] = value - end - end - - # - # @example - # Pry::Config.from_hash(foo: 1) == {'foo' => 1} # => true - # Pry::Config.from_hash(foo: 1) == Pry::Config.from_hash(foo: 1) # => true - # - # @param [Hash, #to_h, #to_hash] other - # Compares `other` against self. - # - # @return [Boolean] - # True if self and `other` are considered `eql?`, otherwise false. - # - def ==(other) - return false unless other - - @lookup == __try_convert_to_hash(other) - end - alias eql? == - - # - # @example - # c = Pry::Config.from_hash(foo: 1) - # c.key?(:foo) # => true - # c.key?('foo') # => true - # - # @param [#to_s] key - # - # @return [Boolean] - # True if `key` is stored in self, otherwise false. - # - def key?(key) - key = key.to_s - @lookup.key?(key) - end - - # - # Clears the contents of self. - # - # @return [void] - # - def clear - @lookup.clear - true - end - - # - # @return [Array<String>] - # An array of keys being stored in self. - # - def keys - @lookup.keys - end - - # - # Eagerly loads keys into self directly from {#last_default}. - # - # @example - # [1] pry(main)> pry_instance.config.keys.size - # => 13 - # [2] pry(main)> pry_instance.config.eager_load!; - # [warning] Pry.config.exception_whitelist is deprecated, - # please use Pry.config.unrescued_exceptions instead. - # [3] pry(main)> pry_instance.config.keys.size - # => 40 - # - # @return [Array<String>, nil] - # An array of keys inserted into self, or nil if {#last_default} is nil. - # - def eager_load! - return unless last_default - - last_default.keys.each { |key| self[key] = public_send(key) } - end - - # - # @example - # # pry_instance.config -> Pry.config -> Pry::Config.defaults - # [1] pry(main)> pry_instance.config.last_default - # - # @return [Pry::Config::Behaviour] - # The last linked default, or nil if there is none. - # - def last_default - last = @default - last = last.default while last && last.default - last - end - - # - # @return [Hash] - # A duplicate copy of the Hash used by self. - # - def to_hash - @lookup.dup - end - alias to_h to_hash - - def inspect - key_str = keys.map { |key| "'#{key}'" }.join(",") - "#<#{__clip_inspect(self)} keys=[#{key_str}] default=#{@default.inspect}>" - end - - def pretty_print(queue) - queue.text(inspect[1..-1].gsub(INSPECT_REGEXP, "default=<")) - end - - # rubocop:disable Style/MethodMissingSuper - def method_missing(method_name, *args, &block) - name = method_name.to_s - if name[-1] == ASSIGNMENT - short_name = name[0..-2] - self[short_name] = args[0] - elsif key?(name) - self[name] - elsif @default.respond_to?(method_name) - value = @default.public_send(method_name, *args, &block) - self[name] = __dup(value) - end - end - # rubocop:enable Style/MethodMissingSuper - - def respond_to_missing?(key, include_all = false) - key = key.to_s.chomp(ASSIGNMENT) - key?(key) || @default.respond_to?(key) || super(key, include_all) - end - - private - - def __clip_inspect(obj) - format("#{obj.class}:0x%<id>x", id: obj.object_id) - end - - def __try_convert_to_hash(obj) - if obj.is_a?(Hash) - obj - elsif obj.respond_to?(:to_h) - obj.to_h - elsif obj.respond_to?(:to_hash) - obj.to_hash - end - end - - def __dup(value) - if NODUP.any? { |klass| value.is_a?(klass) } - value - else - value.dup - end - end - - def __push(key, value) - unless singleton_class.method_defined? key - define_singleton_method(key) { self[key] } - define_singleton_method("#{key}=") { |val| @lookup[key] = val } - end - @lookup[key] = value - end - - def __remove(key) - @lookup.delete(key) - end - end - end -end diff --git a/lib/pry/config/convenience.rb b/lib/pry/config/convenience.rb deleted file mode 100644 index 5560b82f..00000000 --- a/lib/pry/config/convenience.rb +++ /dev/null @@ -1,28 +0,0 @@ -class Pry - class Config < Pry::BasicObject - module Convenience - SHORTCUTS = [ - :input, - :output, - :commands, - :print, - :exception_handler, - :hooks, - :color, - :pager, - :editor, - :memory_size, - :extra_sticky_locals - ].freeze - - def config_shortcut(*names) - names.each do |name| - reader = name - setter = "#{name}=" - define_method(reader) { config.public_send(name) } - define_method(setter) { |value| config.public_send(setter, value) } - end - end - end - end -end diff --git a/lib/pry/config/lazy.rb b/lib/pry/config/lazy.rb deleted file mode 100644 index 9072a5e5..00000000 --- a/lib/pry/config/lazy.rb +++ /dev/null @@ -1,27 +0,0 @@ -class Pry - class Config < Pry::BasicObject - # The primary purpose for instances of this class is to be used as a - # configuration value that is computed upon each access, see {Pry.lazy} - # for more examples. - # - # @example - # num = 19 - # pry_instance.config.foo = Pry::Config::Lazy.new(&proc { num += 1 }) - # pry_instance.config.foo # => 20 - # pry_instance.config.foo # => 21 - # pry_instance.config.foo # => 22 - # - # @api private - # @since v0.12.0 - class Lazy - def initialize(&block) - @block = block - end - - # @return [Object] - def call - @block.call - end - end - end -end diff --git a/lib/pry/config/lazy_value.rb b/lib/pry/config/lazy_value.rb new file mode 100644 index 00000000..8c2330ac --- /dev/null +++ b/lib/pry/config/lazy_value.rb @@ -0,0 +1,27 @@ +class Pry + class Config + # LazyValue is a Proc (block) wrapper. It is meant to be used as a + # configuration value. Subsequent `#call` calls always evaluate the given + # block. + # + # @example + # num = 19 + # value = Pry::Config::LazyValue.new { num += 1 } + # value.foo # => 20 + # value.foo # => 21 + # value.foo # => 22 + # + # @api private + # @since ?.?.? + # @see Pry::Config::MemoizedValue + class LazyValue + def initialize(&block) + @block = block + end + + def call + @block.call + end + end + end +end diff --git a/lib/pry/config/memoized_value.rb b/lib/pry/config/memoized_value.rb new file mode 100644 index 00000000..a8f61d15 --- /dev/null +++ b/lib/pry/config/memoized_value.rb @@ -0,0 +1,28 @@ +class Pry + class Config + # MemoizedValue is a Proc (block) wrapper. It is meant to be used as a + # configuration value. Subsequent `#call` calls return the same memoized + # result. + # + # @example + # num = 19 + # value = Pry::Config::MemoizedValue.new { num += 1 } + # value.call # => 20 + # value.call # => 20 + # value.call # => 20 + # + # @api private + # @since ?.?.? + # @see Pry::Config::LazyValue + class MemoizedValue + def initialize(&block) + @block = block + @call = nil + end + + def call + @call ||= @block.call + end + end + end +end diff --git a/lib/pry/config/value.rb b/lib/pry/config/value.rb new file mode 100644 index 00000000..3afec386 --- /dev/null +++ b/lib/pry/config/value.rb @@ -0,0 +1,22 @@ +class Pry + class Config + # Value holds a value for the given attribute and decides how it should + # be read. Procs get called, other values are returned as is. + # + # @since ?.?.? + # @api private + class Value + def initialize(value) + @value = value + end + + def call + unless [Config::MemoizedValue, Config::LazyValue].include?(@value.class) + return @value + end + + @value.call + end + end + end +end diff --git a/lib/pry/history.rb b/lib/pry/history.rb index ad1c590d..17451bd1 100644 --- a/lib/pry/history.rb +++ b/lib/pry/history.rb @@ -55,7 +55,7 @@ class Pry return line if line == last_line @history << line - @saver.call(line) if !should_ignore?(line) && Pry.config.history.should_save + @saver.call(line) if !should_ignore?(line) && Pry.config.history_save line end @@ -95,17 +95,17 @@ class Pry private # Check if the line match any option in the histignore - # [Pry.config.history.histignore] + # [Pry.config.history_ignorelist] # @return [Boolean] a boolean that notifies if the line was found in the # histignore array. def should_ignore?(line) - hist_ignore = Pry.config.history.histignore + hist_ignore = Pry.config.history_ignorelist return false if hist_ignore.nil? || hist_ignore.empty? hist_ignore.any? { |p| line.to_s.match(p) } end - # The default loader. Yields lines from `Pry.history.config.file`. + # The default loader. Yields lines from `Pry.config.history_file`. def read_from_file path = history_file_path @@ -114,7 +114,7 @@ class Pry warn "Unable to read history file: #{error.message}" end - # The default saver. Appends the given line to `Pry.history.config.file`. + # The default saver. Appends the given line to `Pry.config.history_file`. def save_to_file(line) history_file.puts line if history_file end @@ -137,7 +137,7 @@ class Pry end def history_file_path - File.expand_path(@file_path || Pry.config.history.file) + File.expand_path(@file_path || Pry.config.history_file) end def invalid_readline_line?(line) diff --git a/lib/pry/prompt.rb b/lib/pry/prompt.rb index 1792f59f..906a5f01 100644 --- a/lib/pry/prompt.rb +++ b/lib/pry/prompt.rb @@ -34,13 +34,6 @@ class Pry # @since v0.11.0 # @api public class Prompt - # @return [String] - DEFAULT_NAME = 'pry'.freeze - - # @return [Array<Object>] the list of objects that are known to have a - # 1-line #inspect output suitable for prompt - SAFE_CONTEXTS = [String, Numeric, Symbol, nil, true, false].freeze - # A Hash that holds all prompts. The keys of the Hash are prompt # names, the values are Hash instances of the format {:description, :value}. @prompts = {} diff --git a/lib/pry/pry_class.rb b/lib/pry/pry_class.rb index a58e8bab..c00c6ae1 100644 --- a/lib/pry/pry_class.rb +++ b/lib/pry/pry_class.rb @@ -30,27 +30,13 @@ class Pry def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins - extend Pry::Config::Convenience - config_shortcut(*Pry::Config.shortcuts) - - def prompt=(value) - config.prompt = value - end - - def prompt - config.prompt - end - - def history - return @history if @history - - @history = - if defined?(Pry.config.input::HISTORY) - History.new(history: Pry.config.input::HISTORY) - else - History.new - end - end + def_delegators( + :@config, :input, :input=, :output, :output=, :commands, + :commands=, :print, :print=, :exception_handler, :exception_handler=, + :hooks, :hooks=, :color, :color=, :pager, :pager=, :editor, :editor=, + :memory_size, :memory_size=, :extra_sticky_locals, :extra_sticky_locals=, + :prompt, :prompt=, :history, :history= + ) # # @example @@ -162,7 +148,7 @@ you can add "Pry.config.windows_console_warning = false" to your pryrc. @session_finalized = true load_plugins if Pry.config.should_load_plugins load_requires if Pry.config.should_load_requires - load_history if Pry.config.history.should_load + load_history if Pry.config.history_load load_traps if Pry.config.should_trap_interrupts load_win32console if Helpers::Platform.windows? && !Helpers::Platform.windows_ansi? end @@ -342,7 +328,7 @@ Readline version #{Readline::VERSION} detected - will not auto_resize! correctly @initial_session = true @session_finalized = nil - self.config = Pry::Config.new Pry::Config.defaults + self.config = Pry::Config.new self.cli = false self.current_line = 1 self.line_buffer = [""] @@ -401,24 +387,6 @@ Readline version #{Readline::VERSION} detected - will not auto_resize! correctly ensure Thread.current[:pry_critical_section] -= 1 end - - # Wraps a block in a named block called `Pry::Config::Lazy`. This is used for - # dynamic config values, which are calculated every time - # {Pry::Config::Lazy#call} is called. - # - # @example - # # pryrc - # Pry.config.prompt_name = Pry.lazy { rand(100) } - # - # # Session - # [1] 96(main)> - # [2] 19(main)> - # [3] 80(main)> - # - # @return [#call] - def self.lazy(&block) - Pry::Config::Lazy.new(&block) - end end Pry.init diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index 03840142..a6f87a7f 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -25,6 +25,8 @@ require 'ostruct' # rubocop:disable Metrics/ClassLength class Pry + extend Pry::Forwardable + attr_accessor :binding_stack attr_accessor :custom_completions attr_accessor :eval_string @@ -45,8 +47,13 @@ class Pry attr_reader :config - extend Pry::Config::Convenience - config_shortcut(*Pry::Config.shortcuts) + def_delegators( + :@config, :input, :input=, :output, :output=, :commands, + :commands=, :print, :print=, :exception_handler, :exception_handler=, + :hooks, :hooks=, :color, :color=, :pager, :pager=, :editor, :editor=, + :memory_size, :memory_size=, :extra_sticky_locals, :extra_sticky_locals= + ) + EMPTY_COMPLETIONS = [].freeze # Create a new {Pry} instance. @@ -75,8 +82,7 @@ class Pry @eval_string = "" @backtrace = options.delete(:backtrace) || caller target = options.delete(:target) - @config = Pry::Config.new - config.merge!(options) + @config = self.class.config.merge(options) push_prompt(config.prompt) @input_ring = Pry::Ring.new(config.memory_size) @output_ring = Pry::Ring.new(config.memory_size) diff --git a/lib/pry/testable.rb b/lib/pry/testable.rb index 1a16ec26..5dbb9269 100644 --- a/lib/pry/testable.rb +++ b/lib/pry/testable.rb @@ -34,20 +34,6 @@ class Pry end end - TEST_DEFAULTS = { - color: false, - pager: false, - should_load_rc: false, - should_load_local_rc: false, - correct_indent: false, - collison_warning: false, - history: { - should_load: false, - should_save: false - } - }.freeze - private_constant :TEST_DEFAULTS - # # Sets various configuration options that make Pry optimal for a test # environment, see source code for complete details. @@ -55,8 +41,17 @@ class Pry # @return [void] # def self.set_testenv_variables - Pry.config = Pry::Config.from_hash TEST_DEFAULTS, Pry::Config.defaults - Pry.config.hooks = Pry::Hooks.new + Pry.config = Pry::Config.new.merge( + color: false, + pager: false, + should_load_rc: false, + should_load_local_rc: false, + correct_indent: false, + collision_warning: false, + history_save: false, + history_load: false, + hooks: Pry::Hooks.new + ) end # @@ -65,7 +60,7 @@ class Pry # @return [void] # def self.unset_testenv_variables - Pry.config = Pry::Config.from_hash({}, Pry::Config.defaults) + Pry.config = Pry::Config.new end end end diff --git a/spec/command_spec.rb b/spec/command_spec.rb index b01cff07..56ee27b3 100644 --- a/spec/command_spec.rb +++ b/spec/command_spec.rb @@ -480,7 +480,7 @@ RSpec.describe Pry::Command do subject { Class.new(described_class).new(pry_instance: Pry.new) } - it "returns a state hash" do + it "returns a state object" do expect(subject.state).to be_an(OpenStruct) end diff --git a/spec/commands/edit_spec.rb b/spec/commands/edit_spec.rb index 114906f6..cc741053 100644 --- a/spec/commands/edit_spec.rb +++ b/spec/commands/edit_spec.rb @@ -195,7 +195,7 @@ describe "edit" do end it "should reload the file" do - Pry.config.editor = lambda { |file, _line| + @t.pry.config.editor = lambda { |file, _line| File.open(file, 'w') { |f| f << "FOO = 'BAR'" } nil } @@ -244,7 +244,7 @@ describe "edit" do describe "with --patch" do # Original source code must be untouched. it "should apply changes only in memory (monkey patching)" do - Pry.config.editor = lambda { |file, _line| + @t.pry.config.editor = lambda { |file, _line| File.open(file, 'w') { |f| f << "FOO3 = 'PIYO'" } @patched_def = File.open(file, 'r').read nil @@ -265,7 +265,7 @@ describe "edit" do describe "with --ex NUM" do before do - Pry.config.editor = proc do |file, line| + @t.pry.config.editor = proc do |file, line| @__ex_file__ = file @__ex_line__ = line nil @@ -341,7 +341,7 @@ describe "edit" do end it "should evaluate the expression" do - Pry.config.editor = lambda { |file, _line| + @t.pry.config.editor = lambda { |file, _line| File.open(file, 'w') { |f| f << "'FOO'\n" } nil } @@ -350,7 +350,7 @@ describe "edit" do end it "should ignore -n for tempfiles" do - Pry.config.editor = lambda { |file, _line| + @t.pry.config.editor = lambda { |file, _line| File.open(file, 'w') { |f| f << "'FOO'\n" } nil } @@ -359,7 +359,7 @@ describe "edit" do end it "should not evaluate a file with -n" do - Pry.config.editor = lambda { |file, _line| + @t.pry.config.editor = lambda { |file, _line| File.open(file, 'w') { |f| f << "'FOO'\n" } nil } @@ -374,7 +374,7 @@ describe "edit" do it "should write the evaluated command to history" do quote = 'history repeats itself, first as tradegy...' - Pry.config.editor = lambda { |file, _line| + @t.pry.config.editor = lambda { |file, _line| File.open(file, 'w') do |f| f << quote end diff --git a/spec/commands/hist_spec.rb b/spec/commands/hist_spec.rb index 29315cba..558b4f99 100644 --- a/spec/commands/hist_spec.rb +++ b/spec/commands/hist_spec.rb @@ -176,13 +176,13 @@ describe "hist" do describe "sessions" do before do - @old_file = Pry.config.history.file - Pry.config.history.file = File.expand_path('spec/fixtures/pry_history') + @old_file = Pry.config.history_file + Pry.config.history_file = File.expand_path('spec/fixtures/pry_history') @hist.load end after do - Pry.config.history.file = @old_file + Pry.config.history_file = @old_file end it "displays history only for current session" do @@ -202,7 +202,7 @@ describe "hist" do end it "should not display histignore words in history" do - Pry.config.history.histignore = [ + Pry.config.history_ignorelist = [ "well", "hello", "beautiful", diff --git a/spec/commands/show_doc_spec.rb b/spec/commands/show_doc_spec.rb index 82e6b208..e0bba4da 100644 --- a/spec/commands/show_doc_spec.rb +++ b/spec/commands/show_doc_spec.rb @@ -178,14 +178,10 @@ describe "show-doc" do def decolumnize(output); end end - begin - t = pry_tester(binding) - Pry.config.color = true - expect(t.eval("show-doc _c#decolumnize")).to match(/ls -l \$HOME/) - expect(t.eval("show-doc _c#decolumnize")).not_to match(/`ls -l \$HOME`/) - ensure - Pry.config.color = false - end + t = pry_tester(binding) + t.pry.config.color = true + expect(t.eval("show-doc _c#decolumnize")).to match(/ls -l \$HOME/) + expect(t.eval("show-doc _c#decolumnize")).not_to match(/`ls -l \$HOME`/) end end diff --git a/spec/config/attributable_spec.rb b/spec/config/attributable_spec.rb new file mode 100644 index 00000000..c0c2b167 --- /dev/null +++ b/spec/config/attributable_spec.rb @@ -0,0 +1,27 @@ +RSpec.describe Pry::Config::Attributable do + subject { klass.new } + + describe "#attribute" do + let(:klass) do + Class.new do + extend Pry::Config::Attributable + attribute :foo + end + end + + it "creates a reader attribute for the given name" do + expect(klass.instance_method(:foo)).to be_a(UnboundMethod) + end + + it "creates a writer attribute for the given name" do + expect(klass.instance_method(:foo=)).to be_a(UnboundMethod) + end + + context "and when the attribute is invoked" do + it "sends the 'call' message to the value" do + expect_any_instance_of(Pry::Config::Value).to receive(:call) + subject.foo + end + end + end +end diff --git a/spec/config/behavior_spec.rb b/spec/config/behavior_spec.rb deleted file mode 100644 index 9a789a16..00000000 --- a/spec/config/behavior_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -RSpec.describe Pry::Config::Behavior do - let(:behavior) do - Class.new do - include Pry::Config::Behavior - end - end - - describe "#last_default" do - it "returns the last default" do - last = behavior.from_hash({}, nil) - middle = behavior.from_hash({}, last) - expect(behavior.from_hash({}, middle).last_default).to be(last) - end - end - - describe "#eager_load!" do - it "returns nil when the default is nil" do - expect(behavior.from_hash({}, nil).eager_load!).to be(nil) - end - end -end diff --git a/spec/config/lazy_value_spec.rb b/spec/config/lazy_value_spec.rb new file mode 100644 index 00000000..dc2aaa1e --- /dev/null +++ b/spec/config/lazy_value_spec.rb @@ -0,0 +1,9 @@ +RSpec.describe Pry::Config::LazyValue do + describe "#call" do + subject { described_class.new { rand } } + + it "doesn't memoize the result of call" do + expect(subject.call).not_to eq(subject.call) + end + end +end diff --git a/spec/config/memoized_value_spec.rb b/spec/config/memoized_value_spec.rb new file mode 100644 index 00000000..1601bff2 --- /dev/null +++ b/spec/config/memoized_value_spec.rb @@ -0,0 +1,9 @@ +RSpec.describe Pry::Config::MemoizedValue do + describe "#call" do + subject { described_class.new { rand } } + + it "memoizes the result of call" do + expect(subject.call).to eq(subject.call) + end + end +end diff --git a/spec/config/value_spec.rb b/spec/config/value_spec.rb new file mode 100644 index 00000000..efb8eca4 --- /dev/null +++ b/spec/config/value_spec.rb @@ -0,0 +1,37 @@ +RSpec.describe Pry::Config::Value do + describe "#call" do + context "when given value is a MemoizedValue" do + subject { described_class.new(Pry::Config::MemoizedValue.new { 123 }) } + + it "calls the MemoizedLazy object" do + expect(subject.call).to eq(123) + end + end + + context "when given value is a LazyValue" do + subject { described_class.new(Pry::Config::LazyValue.new { 123 }) } + + it "calls the LazyValue object" do + expect(subject.call).to eq(123) + end + end + + context "when given value is a Proc" do + let(:callable) { proc {} } + + subject { described_class.new(callable) } + + it "returns the value as is" do + expect(subject.call).to eq(callable) + end + end + + context "when given value is a non-callable object" do + subject { described_class.new('test') } + + it "returns the value as is" do + expect(subject.call).to eq('test') + end + end + end +end diff --git a/spec/config_spec.rb b/spec/config_spec.rb index a4e09613..1cd9cdb2 100644 --- a/spec/config_spec.rb +++ b/spec/config_spec.rb @@ -1,289 +1,134 @@ RSpec.describe Pry::Config do - describe ".from_hash" do - it "returns an object without a default" do - local = described_class.from_hash({}) - expect(local.default).to eq(nil) - end - - it "returns an object with a default" do - default = described_class.new(nil) - local = described_class.from_hash({}, default) - expect(local.default).to eq(local) - end + specify { expect(subject.input).to respond_to(:readline) } + specify { expect(subject.output).to be_an(IO) } + specify { expect(subject.commands).to be_a(Pry::CommandSet) } + specify { expect(subject.prompt_name).to be_a(String) } + specify { expect(subject.prompt).to be_a(Pry::Prompt) } + specify { expect(subject.prompt_safe_contexts).to be_an(Array) } + specify { expect(subject.print).to be_a(Method) } + specify { expect(subject.quiet).to be(true).or be(false) } + specify { expect(subject.exception_handler).to be_a(Method) } + specify { expect(subject.unrescued_exceptions).to be_an(Array) } + specify { expect(subject.hooks).to be_a(Pry::Hooks) } + specify { expect(subject.pager).to be(true).or be(false) } + specify { expect(subject.system).to be_a(Method) } + specify { expect(subject.color).to be(true).or be(false) } + specify { expect(subject.default_window_size).to be_a(Numeric) } + specify { expect(subject.editor).to be_a(String) } + specify { expect(subject.should_load_rc).to be(true).or be(false) } + specify { expect(subject.should_load_local_rc).to be(true).or be(false) } + specify { expect(subject.should_trap_interrupts).to be(true).or be(false) } + specify { expect(subject.disable_auto_reload).to be(true).or be(false) } + specify { expect(subject.command_prefix).to be_a(String) } + specify { expect(subject.auto_indent).to be(true).or be(false) } + specify { expect(subject.correct_indent).to be(true).or be(false) } + specify { expect(subject.collision_warning).to be(true).or be(false) } + specify { expect(subject.output_prefix).to be_a(String) } + specify { expect(subject.requires).to be_an(Array) } + specify { expect(subject.should_load_requires).to be(true).or be(false) } + specify { expect(subject.should_load_plugins).to be(true).or be(false) } + specify { expect(subject.windows_console_warning).to be(true).or be(false) } + specify { expect(subject.control_d_handler).to be_a(Method) } + specify { expect(subject.memory_size).to be_a(Numeric) } + specify { expect(subject.extra_sticky_locals).to be_a(Hash) } + specify { expect(subject.command_completions).to be_a(Proc) } + specify { expect(subject.file_completions).to be_a(Proc) } + specify { expect(subject.ls).to be_an(OpenStruct) } + specify { expect(subject.completer).to eq(Pry::InputCompleter) } + specify { expect(subject.history).to be_a(Pry::History) } + specify { expect(subject.history_save).to eq(true).or be(false) } + specify { expect(subject.history_load).to eq(true).or be(false) } + specify { expect(subject.history_file).to be_a(String) } + specify { expect(subject.exec_string).to be_a(String) } - it "recursively walks a Hash" do - h = { 'foo1' => { 'foo2' => { 'foo3' => 'foobar' } } } - default = described_class.from_hash(h) - expect(default.foo1).to be_instance_of(described_class) - expect(default.foo1.foo2).to be_instance_of(described_class) - end + describe "#merge!" do + it "merges given hash with the config instance" do + subject.merge!(output_prefix: '~> ', exec_string: '!') - it "recursively walks an Array" do - c = described_class.from_hash(ary: [{ number: 2 }, Object]) - expect(c.ary[0].number).to eq(2) - expect(c.ary[1]).to eq(Object) + expect(subject.output_prefix).to eq('~> ') + expect(subject.exec_string).to eq('!') end - end - describe "bug #1552" do - specify( - "a local key has precendence over its default when the stored value is false" - ) do - local = described_class.from_hash({}, described_class.from_hash('color' => true)) - local.color = false - expect(local.color).to eq(false) + it "returns self" do + config = subject.merge!(output_prefix: '~> ') + expect(subject).to eql(config) end - end - describe "bug #1277" do - specify "a local key has precendence over an inherited method of the same name" do - local = described_class.from_hash(output: 'foobar') - local.extend( - Module.new do - def output - 'broken' - end - end - ) - expect(local.output).to eq('foobar') - end - end + context "when an undefined option is given" do + it "adds the option to the config" do + subject.merge!(new_option: 1, other_option: 2) - describe "reserved keys" do - it "raises ReservedKeyError on assignment of a reserved key" do - local = described_class.new - local.instance_variable_get(:@reserved_keys).each do |key| - expect { local[key] = 1 }.to raise_error(described_class::ReservedKeyError) + expect(subject.new_option).to eq(1) + expect(subject.other_option).to eq(2) end end end - describe "traversal to parent" do - it "traverses back to the parent when a local key is not found" do - local = described_class.new described_class.from_hash(foo: 1) - expect(local.foo).to eq(1) + describe "#merge" do + it "returns a new config object" do + expect(subject).not_to equal(subject.merge(new_option: 1, other_option: 2)) end - it "stores a local key and prevents traversal to the parent" do - local = described_class.new described_class.from_hash(foo: 1) - local.foo = 2 - expect(local.foo).to eq(2) - end + it "doesn't mutate the original config" do + subject.merge(new_option: 1, other_option: 2) - it "traverses through a chain of parents" do - root = described_class.from_hash(foo: 21) - local1 = described_class.new(root) - local2 = described_class.new(local1) - local3 = described_class.new(local2) - expect(local3.foo).to eq(21) - end - - it "stores a local copy of the parents hooks upon accessing them" do - parent = described_class.from_hash(hooks: "parent_hooks") - local = described_class.new parent - local.hooks.gsub! 'parent', 'local' - expect(local.hooks).to eq 'local_hooks' - expect(parent.hooks).to eq('parent_hooks') + expect(subject).not_to respond_to(:new_option) + expect(subject).not_to respond_to(:other_option) end end - describe "#respond_to_missing?" do - before do - @config = described_class.new(nil) + describe "#method_missing" do + context "when invoked method ends with =" do + it "assigns a new custom option" do + subject.foo = 1 + expect(subject.foo).to eq(1) + end end - it "returns a Method object for a dynamic key" do - @config["key"] = 1 - method_obj = @config.method(:key) - expect(method_obj.name).to eq :key - expect(method_obj.call).to eq(1) + context "when invoked method is not an option" do + it "raises NoMethodError" do + expect { subject.foo }.to raise_error(NoMethodError) + end end - it "returns a Method object for a setter on a parent" do - config = described_class.from_hash({}, described_class.from_hash(foo: 1)) - expect(config.method(:foo=)).to be_an_instance_of(Method) + context "when invoked method is a LazyValue" do + it "defines a callable attribute" do + subject.foo = Pry::Config::LazyValue.new { 1 } + expect(subject.foo).to eq(1) + end end end describe "#respond_to?" do - before do - @config = described_class.new(nil) - end - - it "returns true for a local key" do - @config.zzfoo = 1 - expect(@config.respond_to?(:zzfoo)).to eq(true) - end - - it "returns false for an unknown key" do - expect(@config.respond_to?(:blahblah)).to eq(false) - end - end - - describe "#default" do - it "returns nil" do - local = described_class.new(nil) - expect(local.default).to eq(nil) - end - - it "returns the default" do - default = described_class.new(nil) - local = described_class.new(default) - expect(local.default).to eq(default) - end - end - - describe "#keys" do - it "returns an array of local keys" do - root = described_class.from_hash({ zoo: "boo" }, nil) - local = described_class.from_hash({ foo: "bar" }, root) - expect(local.keys).to eq(["foo"]) - end - end - - describe "#==" do - it "compares equality through the underlying lookup table" do - local1 = described_class.new(nil) - local2 = described_class.new(nil) - local1.foo = "hi" - local2.foo = "hi" - expect(local1).to eq(local2) - end - - it "compares equality against an object who does not implement #to_hash" do - local1 = described_class.new(nil) - expect(local1).not_to eq(Object.new) - end - - it "returns false when compared against nil" do - # rubocop:disable Style/NilComparison - expect(described_class.new(nil) == nil).to eq(false) - # rubocop:enable Style/NilComparison - end - end - - describe '#forget' do - it 'restores a key to its default value' do - last_default = described_class.from_hash(a: 'c') - middle_default = described_class.from_hash({ a: 'b' }, last_default) - c = described_class.from_hash({ a: 'a' }, middle_default) - c.forget(:a) - expect(c.a).to eq('c') - end - end - - describe "#to_hash" do - it "provides a copy of local key & value pairs as a Hash" do - local = described_class.new described_class.from_hash(bar: true) - local.foo = "21" - expect(local.to_hash).to eq("foo" => "21") - end - - it "returns a duplicate of the lookup table" do - local = described_class.new(nil) - local.to_hash["foo"] = 42 - expect(local.foo).not_to eq(42) - end - end - - describe "#merge!" do - before do - @config = described_class.new(nil) - end - - it "merges an object who returns a Hash through #to_hash" do - obj = Class.new do - def to_hash - { epoch: 1 } - end - end.new - @config.merge!(obj) - expect(@config.epoch).to eq(1) - end - - it "merges an object who returns a Hash through #to_h" do - obj = Class.new do - def to_h - { epoch: 2 } - end - end.new - @config.merge!(obj) - expect(@config.epoch).to eq(2) - end - - it "merges a Hash" do - @config[:epoch] = 420 - expect(@config.epoch).to eq(420) - end - - it "raises a TypeError for objects who can't become a Hash" do - expect { @config.merge!(Object.new) }.to raise_error TypeError - end - end - - describe "#clear" do - before do - @local = described_class.new(nil) + context "when checking an undefined option" do + it "returns false" do + expect(subject.respond_to?(:foo)).to be(false) + end end - it "returns true" do - expect(@local.clear).to eq(true) - end + context "when checking a defined option" do + before { subject.foo = 1 } - it "clears local assignments" do - @local.foo = 1 - @local.clear - expect(@local.to_hash).to eq({}) - end - end + it "returns true for the reader" do + expect(subject.respond_to?(:foo)).to be(true) + end - describe "#[]=" do - it "stores keys as strings" do - local = described_class.from_hash({}) - local[:zoo] = "hello" - expect(local.to_hash).to eq("zoo" => "hello") + it "returns true for the writer" do + expect(subject.respond_to?(:foo=)).to be(true) + end end end describe "#[]" do - it "traverses back to a default" do - default = described_class.from_hash(k: 1) - local = described_class.new(default) - expect(local['k']).to eq(1) - end - - it "traverses back to a default (2 deep)" do - default1 = described_class.from_hash(k: 1) - default2 = described_class.from_hash({}, default1) - local = described_class.new(default2) - expect(local['k']).to eq(1) - end - - it "traverses back to a default that doesn't exist, and returns nil" do - local = described_class.from_hash({}, nil) - expect(local['output']).to eq(nil) + it "reads the config value" do + expect_any_instance_of(Pry::Config::Value).to receive(:call) + subject[:foo] = 1 + subject[:foo] end - context "when returning a Pry::Config::Lazy object" do - it "invokes #call on it" do - c = described_class.from_hash foo: Pry.lazy { 10 } - expect(c['foo']).to eq(10) - end - - it "invokes #call upon each access" do - c = described_class.from_hash foo: Pry.lazy { 'foo' } - expect(c['foo']).to_not equal(c['foo']) - end - end - end - - describe "#eager_load!" do - it "eagerly loads keys from the last default into self" do - last_default = described_class.from_hash(foo: 1, bar: 2, baz: 3) - c = described_class.from_hash({}, last_default) - expect(c.keys.size).to eq(0) - c.eager_load! - expect(c.keys.size).to eq(3) + it "returns the config value" do + subject[:foo] = 1 + expect(subject[:foo]).to eq(1) end end end diff --git a/spec/history_spec.rb b/spec/history_spec.rb index f69fea0c..0e3f4b6e 100644 --- a/spec/history_spec.rb +++ b/spec/history_spec.rb @@ -68,15 +68,15 @@ RSpec.describe Pry::History do describe "#clear" do before do - @old_file = Pry.config.history.file + @old_file = Pry.config.history_file @hist_file_path = File.expand_path('spec/fixtures/pry_history') - Pry.config.history.file = @hist_file_path + Pry.config.history_file = @hist_file_path Pry.history.clear Pry.load_history end after do - Pry.config.history.file = @old_file + Pry.config.history_file = @old_file end it "clears this session's history" do @@ -130,12 +130,12 @@ RSpec.describe Pry::History do before do @histfile = Tempfile.new(%w[pryhistory txt]) @history = Pry::History.new(file_path: @histfile.path) - Pry.config.history.should_save = true + Pry.config.history_save = true end after do @histfile.close(true) - Pry.config.history.should_save = false + Pry.config.history_save = false end it "saves lines to a file as they are written" do @@ -152,7 +152,7 @@ RSpec.describe Pry::History do end it "should not write histignore words to the history file" do - Pry.config.history.histignore = ["ls", /hist*/, 'exit'] + Pry.config.history_ignorelist = ["ls", /hist*/, 'exit'] @history.push "ls" @history.push "hist" @history.push "kakaroto" @@ -164,8 +164,8 @@ RSpec.describe Pry::History do end describe "expanding the history file path" do - before { Pry.config.history.should_save = true } - after { Pry.config.history.should_save = false } + before { Pry.config.history_save = true } + after { Pry.config.history_save = false } it "recognizes ~ (#1262)" do # This is a pretty dumb way of testing this, but at least it shouldn't @@ -193,7 +193,7 @@ RSpec.describe Pry::History do end it "handles #{error_class} failure to write history" do - Pry.config.history.should_save = true + Pry.config.history_save = true expect(File).to receive(:open).with(file_path, "a", 0o600).and_raise(error_class) expect(history).to receive(:warn).with(/Unable to write history file:/) expect { history.push("anything") }.to_not raise_error diff --git a/spec/prompt_spec.rb b/spec/prompt_spec.rb index 9e57045f..58616cd5 100644 --- a/spec/prompt_spec.rb +++ b/spec/prompt_spec.rb @@ -90,7 +90,7 @@ describe Pry::Prompt do it "computes prompt name dynamically" do proc = described_class[:default].wait_proc - pry.config.prompt_name = Pry.lazy { enum.next } + pry.config.prompt_name = Pry::Config::LazyValue.new { enum.next } expect(proc.call(Object.new, 1, pry, '>')).to eq('[1] a(#<Object>):1> ') expect(proc.call(Object.new, 1, pry, '>')).to eq('[1] b(#<Object>):1> ') end diff --git a/spec/pry_defaults_spec.rb b/spec/pry_defaults_spec.rb index 133d9b02..24fa54c5 100644 --- a/spec/pry_defaults_spec.rb +++ b/spec/pry_defaults_spec.rb @@ -373,7 +373,7 @@ describe "test Pry defaults" do binding, input: InputTester.new("1", "exit-all"), output: @str_output, - hooks: Pry::Config.defaults.hooks + hooks: Pry::Config.new.hooks ) expect(@str_output.string).to match(/[w]hereami by default/) @@ -384,7 +384,7 @@ describe "test Pry defaults" do input: InputTester.new('exit-all'), output: @str_output, quiet: true, - hooks: Pry::Config.defaults.hooks + hooks: Pry::Config.new.hooks ) expect(@str_output.string).to eq "" diff --git a/spec/pry_output_spec.rb b/spec/pry_output_spec.rb index 2facc4f8..8f905d02 100644 --- a/spec/pry_output_spec.rb +++ b/spec/pry_output_spec.rb @@ -1,6 +1,6 @@ describe Pry do describe "output failsafe" do - after { Pry.config.print = Pry::Config.defaults.print } + after { Pry.config.print = Pry::Config.new.print } it "should catch serialization exceptions" do Pry.config.print = proc { raise "catch-22" } diff --git a/spec/pry_repl_spec.rb b/spec/pry_repl_spec.rb index 5430a0a7..f407240a 100644 --- a/spec/pry_repl_spec.rb +++ b/spec/pry_repl_spec.rb @@ -45,7 +45,7 @@ describe Pry::REPL do it "shouldn't break if we start a nested instance" do ReplTester.start do - input 'Pry.start(10, pry_instance.config)' + input 'Pry.start(10)' output '' prompt(/10.*> $/) |