From 5f37f3f2f54f634d0486d18a2c3849ab64d66a0a Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Sat, 17 Jan 2026 21:49:26 +0900 Subject: [PATCH 1/6] Add custom package support to RelinePac configuration --- README.md | 8 +++- README_ja.md | 7 +++- bin/console | 8 +--- lib/reline_pac/config.rb | 15 ++++++- lib/reline_pac/packages.rb | 1 + lib/reline_pac/packages/custom.rb | 9 ++++ spec/reline_pac/config_spec.rb | 69 +++++++++++++++++++++++++++++++ spec/reline_pac_spec.rb | 2 +- 8 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 lib/reline_pac/packages/custom.rb create mode 100644 spec/reline_pac/config_spec.rb diff --git a/README.md b/README.md index ebea4b3..2a978ba 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,16 @@ Call `RelinePac.configure` during IRB/pry startup (e.g., `~/.irbrc`) and bind ke begin require "reline_pac" RelinePac.configure do |config| + # Apply default keybinds RelinePac::Packages::DEFAULT_KEYBINDS.each do |key, method| config.add_keybind(key, method) end - # override or add your own bindings - # config.add_keybind("\C-r", :fzf_history) + # Add your custom package (method) + config.add_package(:my_custom_method) do |_key| + insert_text("Hello from custom package!") + end + config.add_keybind("\C-x", :my_custom_method) end rescue LoadError # do nothing diff --git a/README_ja.md b/README_ja.md index c50725e..25d116b 100644 --- a/README_ja.md +++ b/README_ja.md @@ -25,8 +25,11 @@ begin config.add_keybind(key, method) end - # 上書きや独自の割り当ても可能 - # config.add_keybind("\C-r", :fzf_history) + # 独自のパッケージ(メソッド)を追加 + config.add_package(:my_custom_method) do |_key| + insert_text("カスタムパッケージからこんにちは!") + end + config.add_keybind("\C-x", :my_custom_method) end rescue LoadError # do nothing diff --git a/bin/console b/bin/console index dcb1b99..2a21a3f 100755 --- a/bin/console +++ b/bin/console @@ -2,15 +2,11 @@ # frozen_string_literal: true require 'bundler/setup' -require 'reline_pac' - -# You can add fixtures and/or initialization code here to make experimenting -# with your gem easier. You can also use a different console, if you like. - require 'irb' +require 'reline_pac' RelinePac.configure do |config| - # デフォルトを適用 + # default keybindings RelinePac::Packages::DEFAULT_KEYBINDS.each do |key, method| config.add_keybind(key, method) end diff --git a/lib/reline_pac/config.rb b/lib/reline_pac/config.rb index 3cdca4f..a9888cb 100644 --- a/lib/reline_pac/config.rb +++ b/lib/reline_pac/config.rb @@ -7,6 +7,19 @@ def initialize Packages.install_all end + # Add a custom package (method) to Reline::LineEditor. + # @param method_name [Symbol] the method name to add + # @yield a block that defines the method body; receives _key as first argument + def add_package(method_name, &block) + return unless block_given? + + Packages::Custom.module_eval do + define_method(method_name, &block) + end + + Reline::LineEditor.prepend(Packages::Custom) unless Reline::LineEditor.ancestors.include?(Packages::Custom) + end + # Add a keybinding that invokes the given LineEditor method symbol. # @param key [String] a string such as "\C-r" # @param method [Symbol] the LineEditor method to invoke @@ -18,7 +31,7 @@ def add_keybind(key, method) private def reline_config - @reline_config ||= Reline.send(:core).config + @reline_config ||= Reline.core.config end end end diff --git a/lib/reline_pac/packages.rb b/lib/reline_pac/packages.rb index 5736a74..5f07e36 100644 --- a/lib/reline_pac/packages.rb +++ b/lib/reline_pac/packages.rb @@ -4,6 +4,7 @@ require_relative 'packages/completion' require_relative 'packages/clipboard' require_relative 'packages/history' +require_relative 'packages/custom' module RelinePac # Packages contains all Reline extensions and their default keybindings. diff --git a/lib/reline_pac/packages/custom.rb b/lib/reline_pac/packages/custom.rb new file mode 100644 index 0000000..3eb92e1 --- /dev/null +++ b/lib/reline_pac/packages/custom.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module RelinePac + module Packages + # Custom holds user-defined packages added via Config#add_package. + module Custom + end + end +end diff --git a/spec/reline_pac/config_spec.rb b/spec/reline_pac/config_spec.rb new file mode 100644 index 0000000..1c31528 --- /dev/null +++ b/spec/reline_pac/config_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe RelinePac::Config do + describe '#add_package' do + it 'adds a custom method to Reline::LineEditor' do + config = described_class.new + + config.add_package(:test_method) do |_key| + 'test result' + end + + # Verify the method was added + line_editor = Reline::LineEditor.allocate + expect(line_editor).to respond_to(:test_method) + end + + it 'allows calling the custom method' do + config = described_class.new + + config.add_package(:custom_insert) do |_key| + insert_text('custom') if respond_to?(:insert_text) + end + + line_editor_class = Class.new do + prepend(Reline::LineEditor.ancestors.find { |m| m.method_defined?(:custom_insert, false) }) + + def insert_text(text) + @inserted = text + end + + attr_reader :inserted + end + + instance = line_editor_class.new + instance.custom_insert(nil) + expect(instance.inserted).to eq('custom') + end + + it 'does not override existing methods' do + config = described_class.new + + # Add first package + config.add_package(:shared_method) do |_key| + 'first' + end + + # Add second package with same method name + config.add_package(:shared_method) do |_key| + 'second' + end + + # The second one should take precedence (prepend behavior) + line_editor = Reline::LineEditor.allocate + expect(line_editor.shared_method(nil)).to eq('second') + end + + it 'does nothing when no block is given' do + config = described_class.new + initial_ancestors = Reline::LineEditor.ancestors.dup + + config.add_package(:no_block_method) + + # Should not add anything + expect(Reline::LineEditor.ancestors.size).to eq(initial_ancestors.size) + end + end +end diff --git a/spec/reline_pac_spec.rb b/spec/reline_pac_spec.rb index fefcd96..9644e32 100644 --- a/spec/reline_pac_spec.rb +++ b/spec/reline_pac_spec.rb @@ -12,7 +12,7 @@ reline_config = double('RelineConfig', add_default_key_binding: nil) # rubocop:disable RSpec/VerifiedDoubles allow(RelinePac::Packages).to receive(:install_all) - allow(Reline).to receive(:send).with(:core).and_return(double(config: reline_config)) + allow(Reline).to receive(:core).and_return(double(config: reline_config)) described_class.configure do |config| config.add_keybind("\C-r", :fzf_history) From af0e41ebb39cbc79cfab3b887d1355be5e8ae163 Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Sat, 17 Jan 2026 22:17:24 +0900 Subject: [PATCH 2/6] Update lib/reline_pac/config.rb Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- lib/reline_pac/config.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/reline_pac/config.rb b/lib/reline_pac/config.rb index a9888cb..c041dbc 100644 --- a/lib/reline_pac/config.rb +++ b/lib/reline_pac/config.rb @@ -11,7 +11,9 @@ def initialize # @param method_name [Symbol] the method name to add # @yield a block that defines the method body; receives _key as first argument def add_package(method_name, &block) - return unless block_given? + unless block_given? + raise ArgumentError, 'add_package requires a block to define the package method body' + end Packages::Custom.module_eval do define_method(method_name, &block) From 7e870105bbdcd46a735d4034f52d3b1273805abe Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Sat, 17 Jan 2026 22:17:36 +0900 Subject: [PATCH 3/6] Update spec/reline_pac/config_spec.rb Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- spec/reline_pac/config_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/reline_pac/config_spec.rb b/spec/reline_pac/config_spec.rb index 1c31528..71e06cd 100644 --- a/spec/reline_pac/config_spec.rb +++ b/spec/reline_pac/config_spec.rb @@ -38,7 +38,7 @@ def insert_text(text) expect(instance.inserted).to eq('custom') end - it 'does not override existing methods' do + it 'allows overriding methods with later definitions' do config = described_class.new # Add first package From 89999002dd7bc5fce756e52a2ce86ead54058277 Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Mon, 19 Jan 2026 21:56:07 +0900 Subject: [PATCH 4/6] Enhance .irbrc and README with detailed configuration options for RelinePac --- README.md | 58 ++++++++----------------------------------------- README_ja.md | 58 ++++++++----------------------------------------- examples/.irbrc | 40 +++++++++++++++++++++++++++++----- 3 files changed, 52 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index c004910..fb01ccf 100644 --- a/README.md +++ b/README.md @@ -16,64 +16,24 @@ Install the gem globally (not in your project's Gemfile): gem install reline_pac ``` -Then add the following to your `~/.irbrc`. This works even in Bundler environments (like `rails console`): - -```ruby -# Check if running in a Bundler environment (e.g., rails c) -if defined?(Bundler) - # Temporarily unbundle to get the system gem path - reline_pac_gem_path = Bundler.with_unbundled_env do - `gem which reline_pac 2> /dev/null`.chomp - end - - unless reline_pac_gem_path.empty? - lib_dir = File.dirname(reline_pac_gem_path) - $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) - end -end - -begin - require 'reline_pac' - RelinePac.configure do |config| - # Apply default keybindings - RelinePac::Packages::DEFAULT_KEYBINDS.each do |key, method| - config.add_keybind(key, method) - end - end - # Add your custom package (method) - # config.add_package(:my_custom_method) do |_key| - # insert_text("Hello from custom package!") - # end - # config.add_keybind("\C-r", :fzf_history) - - # You can override or add custom keybindings - # config.add_keybind("\C-r", :fzf_history) -rescue LoadError - # do nothing -end -``` - -Alternatively, you can download it directly from GitHub: +Then set up your `~/.irbrc`: ```bash +# Download the example configuration curl -o ~/.irbrc https://raw.githubusercontent.com/Syati/reline_pac/main/examples/.irbrc ``` +Or see [examples/.irbrc](examples/.irbrc) for the full configuration code that you can copy and customize. + ## Usage -Add the setup code from the Installation section to your `~/.irbrc` to enable default keybindings. +The example configuration in [examples/.irbrc](examples/.irbrc) provides three options: -### Custom packages -You can add your own custom methods: +1. **Use default keybindings** (recommended): Just use the configuration as-is +2. **Customize keybindings**: Modify individual key bindings to your preference +3. **Add custom packages**: Define your own methods and bind them to keys -```ruby -RelinePac.configure do |config| - config.add_package(:my_custom_method) do |_key| - insert_text("Hello from custom package!") - end - config.add_keybind("\C-x", :my_custom_method) -end -``` +See [examples/.irbrc](examples/.irbrc) for detailed comments and examples. ### Default keybinds - `\C-y` -> `:pbpaste` (uses macOS `pbpaste`) diff --git a/README_ja.md b/README_ja.md index bf2705c..59e0c9c 100644 --- a/README_ja.md +++ b/README_ja.md @@ -16,64 +16,24 @@ gem をグローバルにインストールします(プロジェクトの Gem gem install reline_pac ``` -次に `~/.irbrc` に以下を追加します。Bundler 環境(`rails console` など)でも動作します: - -```ruby -# Check if running in a Bundler environment (e.g., rails c) -if defined?(Bundler) - # Temporarily unbundle to get the system gem path - reline_pac_gem_path = Bundler.with_unbundled_env do - `gem which reline_pac 2> /dev/null`.chomp - end - - unless reline_pac_gem_path.empty? - lib_dir = File.dirname(reline_pac_gem_path) - $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) - end -end - -begin - require 'reline_pac' - RelinePac.configure do |config| - # Apply default keybindings - RelinePac::Packages::DEFAULT_KEYBINDS.each do |key, method| - config.add_keybind(key, method) - end - # 独自のパッケージ(メソッド)を追加 - # config.add_package(:my_custom_method) do |_key| - # insert_text("Hello from custom package!") - # end - # config.add_keybind("\C-x", :my_custom_method) - - # 上書きや独自の割り当ても可能 - # config.add_keybind("\C-r", :fzf_history) - end -rescue LoadError - # do nothing -end -``` - -または、GitHub から直接ダウンロードすることもできます: +次に `~/.irbrc` を設定します: ```bash +# サンプル設定をダウンロード curl -o ~/.irbrc https://raw.githubusercontent.com/Syati/reline_pac/main/examples/.irbrc ``` +または、[examples/.irbrc](examples/.irbrc) の内容をコピー&カスタマイズすることもできます。 + ## 使い方 -インストールセクションの設定例を `~/.irbrc` に追加すれば、デフォルトのキーバインドが利用できます。 +[examples/.irbrc](examples/.irbrc) のサンプル設定には、3つのオプションが用意されています: -### カスタムパッケージ -独自のメソッドを追加できます: +1. **デフォルトのキーバインドを使用**(推奨): 設定をそのまま使用 +2. **キーバインドをカスタマイズ**: 個別のキーバインドを好みに合わせて変更 +3. **カスタムパッケージを追加**: 独自のメソッドを定義してキーにバインド -```ruby -RelinePac.configure do |config| - config.add_package(:my_custom_method) do |_key| - insert_text("Hello from custom package!") - end - config.add_keybind("\C-x", :my_custom_method) -end -``` +詳細とサンプルコードは [examples/.irbrc](examples/.irbrc) を参照してください。 ### デフォルトのキー割り当て - `\C-y` -> `:pbpaste`(macOS の `pbpaste` を使用) diff --git a/examples/.irbrc b/examples/.irbrc index 62680cd..217d58e 100644 --- a/examples/.irbrc +++ b/examples/.irbrc @@ -1,6 +1,8 @@ -# Check if running in a Bundler environment (e.g., rails c) +# RelinePac configuration for IRB/Pry +# This works even in Bundler environments (e.g., rails console) + if defined?(Bundler) - # Temporarily unbundle to get the system gem path + # Access system gem when running under Bundler reline_pac_gem_path = Bundler.with_unbundled_env do `gem which reline_pac 2> /dev/null`.chomp end @@ -13,14 +15,40 @@ end begin require 'reline_pac' + RelinePac.configure do |config| - # Apply default keybindings + # ============================================ + # Option 1: Use default keybindings (recommended for beginners) + # ============================================ + # Default bindings: + # \C-y => pbpaste (paste from clipboard) + # \C-k => pbcopy_kill (copy rest of line to clipboard) + # \C-r => fzf_history (search history with fzf) + # \C-n => completion_next (next completion item) + # \C-p => completion_prev (previous completion item) RelinePac::Packages::DEFAULT_KEYBINDS.each do |key, method| config.add_keybind(key, method) end + + # ============================================ + # Option 2: Customize keybindings + # ============================================ + # If you want to customize, comment out lines 29-31 above, then uncomment and modify below: + # + # config.add_keybind("\C-y", :pbpaste) + # config.add_keybind("\C-k", :pbcopy_kill) + # config.add_keybind("\C-r", :fzf_history) + # config.add_keybind("\C-n", :completion_next) + # config.add_keybind("\C-p", :completion_prev) + + # ============================================ + # Option 3: Add your own custom package + # ============================================ + # config.add_package(:insert_hello) do |_key| + # insert_text("Hello, World!") + # end + # config.add_keybind("\C-x\C-h", :insert_hello) end - # You can override or add custom keybindings - # config.add_keybind("\C-r", :fzf_history) rescue LoadError - # do nothing + # Silently ignore if reline_pac is not installed end From bf4b5b988e0ef175358e7fdd83b3461d607d6117 Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Mon, 19 Jan 2026 21:57:48 +0900 Subject: [PATCH 5/6] Refactor add_package method to simplify block presence check --- lib/reline_pac/config.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/reline_pac/config.rb b/lib/reline_pac/config.rb index c041dbc..0727f31 100644 --- a/lib/reline_pac/config.rb +++ b/lib/reline_pac/config.rb @@ -11,9 +11,7 @@ def initialize # @param method_name [Symbol] the method name to add # @yield a block that defines the method body; receives _key as first argument def add_package(method_name, &block) - unless block_given? - raise ArgumentError, 'add_package requires a block to define the package method body' - end + raise ArgumentError, 'add_package requires a block to define the package method body' unless block_given? Packages::Custom.module_eval do define_method(method_name, &block) From 4b88473515c5ebc403dcb52976ed1aa32b9736ff Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Mon, 19 Jan 2026 22:00:47 +0900 Subject: [PATCH 6/6] Update config_spec to raise ArgumentError when no block is given to add_package --- spec/reline_pac/config_spec.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/spec/reline_pac/config_spec.rb b/spec/reline_pac/config_spec.rb index 71e06cd..f0b4da8 100644 --- a/spec/reline_pac/config_spec.rb +++ b/spec/reline_pac/config_spec.rb @@ -56,14 +56,9 @@ def insert_text(text) expect(line_editor.shared_method(nil)).to eq('second') end - it 'does nothing when no block is given' do + it 'raise ArgumentError when no block is given' do config = described_class.new - initial_ancestors = Reline::LineEditor.ancestors.dup - - config.add_package(:no_block_method) - - # Should not add anything - expect(Reline::LineEditor.ancestors.size).to eq(initial_ancestors.size) + expect { config.add_package(:no_block_method) }.to raise_error(ArgumentError) end end end