Skip to content

Commit

Permalink
Merge pull request rails#51705 from Shopify/update-irb
Browse files Browse the repository at this point in the history
Build Rails console on top of IRB's latest official APIs
  • Loading branch information
rafaelfranca authored May 1, 2024
2 parents 549144b + 4c1f7d8 commit 6b67657
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 162 deletions.
14 changes: 7 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ PATH
railties (7.2.0.alpha)
actionpack (= 7.2.0.alpha)
activesupport (= 7.2.0.alpha)
irb
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
Expand Down Expand Up @@ -288,10 +288,10 @@ GEM
actionpack (>= 6.0.0)
activesupport (>= 6.0.0)
railties (>= 6.0.0)
io-console (0.7.1)
irb (1.11.0)
rdoc
reline (>= 0.3.8)
io-console (0.7.2)
irb (1.13.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
Expand Down Expand Up @@ -415,7 +415,7 @@ GEM
rb-inotify (0.10.1)
ffi (~> 1.0)
rbtree (0.4.6)
rdoc (6.6.2)
rdoc (6.6.3.1)
psych (>= 4.0.0)
redcarpet (3.2.3)
redis (5.0.8)
Expand All @@ -425,7 +425,7 @@ GEM
redis-namespace (1.11.0)
redis (>= 4)
regexp_parser (2.8.3)
reline (0.4.1)
reline (0.5.4)
io-console (~> 0.5)
representable (3.2.0)
declarative (< 0.1.0)
Expand Down
11 changes: 11 additions & 0 deletions railties/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
* Implement Rails console commands and helpers with IRB v1.13's extension APIs

Rails console users will now see `helper`, `controller`, `new_session`, and `app` under
IRB help message's `Helper methods` category. And `reload!` command will be displayed under
the new `Rails console` commands category.

Prior to this change, Rails console's commands and helper methods are added through IRB's
private components and don't show up in its help message, which led to poor discoverability.

*Stan Lo*

* Remove deprecated `Rails::Generators::Testing::Behaviour`.

*Rafael Mendonça França*
Expand Down
65 changes: 4 additions & 61 deletions railties/lib/rails/commands/console/console_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,6 @@

module Rails
class Console
module BacktraceCleaner
def filter_backtrace(bt)
if result = super
Rails.backtrace_cleaner.filter([result]).first
end
end
end

class IRBConsole
def initialize(app)
@app = app

require "irb"
require "irb/completion"

IRB::WorkSpace.prepend(BacktraceCleaner)
IRB::ExtendCommandBundle.include(Rails::ConsoleMethods)
end

def name
"IRB"
end

def start
IRB.setup(nil)

if !Rails.env.local? && !ENV.key?("IRB_USE_AUTOCOMPLETE")
IRB.conf[:USE_AUTOCOMPLETE] = false
end

env = colorized_env
app_name = @app.class.module_parent_name.underscore.dasherize
prompt_prefix = "#{app_name}(#{env})"

IRB.conf[:PROMPT][:RAILS_PROMPT] = {
PROMPT_I: "#{prompt_prefix}> ",
PROMPT_S: "#{prompt_prefix}%l ",
PROMPT_C: "#{prompt_prefix}* ",
RETURN: "=> %s\n"
}

# Respect user's choice of prompt mode.
IRB.conf[:PROMPT_MODE] = :RAILS_PROMPT if IRB.conf[:PROMPT_MODE] == :DEFAULT
IRB::Irb.new.run(IRB.conf)
end

def colorized_env
case Rails.env
when "development"
IRB::Color.colorize("dev", [:BLUE])
when "test"
IRB::Color.colorize("test", [:BLUE])
when "production"
IRB::Color.colorize("prod", [:RED])
else
Rails.env
end
end
end

def self.start(*args)
new(*args).start
end
Expand All @@ -83,7 +23,10 @@ def initialize(app, options = {})

app.load_console

@console = app.config.console || IRBConsole.new(app)
@console = app.config.console || begin
require "rails/commands/console/irb_console"
IRBConsole.new(app)
end
end

def sandbox?
Expand Down
123 changes: 123 additions & 0 deletions railties/lib/rails/commands/console/irb_console.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# frozen_string_literal: true

require "irb/helper_method"
require "irb/command"

module Rails
class Console
class RailsHelperBase < IRB::HelperMethod::Base
include ConsoleMethods
end

class ControllerHelper < RailsHelperBase
description "Gets the helper methods available to the controller."

# This method assumes an +ApplicationController+ exists, and that it extends ActionController::Base.
def execute
helper
end
end

class ControllerInstance < RailsHelperBase
description "Gets a new instance of a controller object."

# This method assumes an +ApplicationController+ exists, and that it extends ActionController::Base.
def execute
controller
end
end

class NewSession < RailsHelperBase
description "Create a new session. If a block is given, the new session will be yielded to the block before being returned."

def execute
new_session
end
end

class AppInstance < RailsHelperBase
description "Reference the global 'app' instance, created on demand. To recreate the instance, pass a non-false value as the parameter."

def execute(create = false)
app(create)
end
end

class Reloader < IRB::Command::Base
include ConsoleMethods

category "Rails console"
description "Reloads the environment."

def execute(*)
reload!
end
end

IRB::HelperMethod.register(:helper, ControllerHelper)
IRB::HelperMethod.register(:controller, ControllerInstance)
IRB::HelperMethod.register(:new_session, NewSession)
IRB::HelperMethod.register(:app, AppInstance)
IRB::Command.register(:reload!, Reloader)

class IRBConsole
def initialize(app)
@app = app

require "irb"
require "irb/completion"
end

def name
"IRB"
end

def start
IRB.setup(nil)

if !Rails.env.local? && !ENV.key?("IRB_USE_AUTOCOMPLETE")
IRB.conf[:USE_AUTOCOMPLETE] = false
end

env = colorized_env
app_name = @app.class.module_parent_name.underscore.dasherize
prompt_prefix = "#{app_name}(#{env})"

IRB.conf[:PROMPT][:RAILS_PROMPT] = {
PROMPT_I: "#{prompt_prefix}> ",
PROMPT_S: "#{prompt_prefix}%l ",
PROMPT_C: "#{prompt_prefix}* ",
RETURN: "=> %s\n"
}

if current_filter = IRB.conf[:BACKTRACE_FILTER]
IRB.conf[:BACKTRACE_FILTER] = -> (backtrace) do
backtrace = current_filter.call(backtrace)
Rails.backtrace_cleaner.filter(backtrace)
end
else
IRB.conf[:BACKTRACE_FILTER] = -> (backtrace) do
Rails.backtrace_cleaner.filter(backtrace)
end
end

# Respect user's choice of prompt mode.
IRB.conf[:PROMPT_MODE] = :RAILS_PROMPT if IRB.conf[:PROMPT_MODE] == :DEFAULT
IRB::Irb.new.run(IRB.conf)
end

def colorized_env
case Rails.env
when "development"
IRB::Color.colorize("dev", [:BLUE])
when "test"
IRB::Color.colorize("test", [:BLUE])
when "production"
IRB::Color.colorize("prod", [:RED])
else
Rails.env
end
end
end
end
end
2 changes: 1 addition & 1 deletion railties/railties.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Gem::Specification.new do |s|
s.add_dependency "rake", ">= 12.2"
s.add_dependency "thor", "~> 1.0", ">= 1.2.2"
s.add_dependency "zeitwerk", "~> 2.6"
s.add_dependency "irb"
s.add_dependency "irb", "~> 1.13"

s.add_development_dependency "actionview", version
end
Loading

0 comments on commit 6b67657

Please sign in to comment.