Skip to content

Commit

Permalink
Update no method error dictionary (#59)
Browse files Browse the repository at this point in the history
* Make dictionnary for no method error more exhaustive

* Use reflect_on_all_associations for getting associations

* Update spec
  • Loading branch information
morissetcl committed Dec 31, 2024
1 parent 47b6b33 commit e1193d6
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 24 deletions.
26 changes: 17 additions & 9 deletions lib/pry-byetypo/exceptions/no_method_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,23 @@ def unknown_from_exception
end

def dictionary
klass_methods = eval(infer_klass).methods # rubocop:disable Security/Eval
# Early return because built_in class does not have access to `instance_methods`.
return klass_methods.map(&:to_s) if built_in_klass

instance_methods = eval(infer_klass).instance_methods(false) # rubocop:disable Security/Eval
instance_methods.push(klass_methods)
.push(ActiveRecord::Base.methods)
.flatten
.map(&:to_s)
@dictionary ||= begin
klass_eval = eval(infer_klass) # rubocop:disable Security/Eval
klass_methods = klass_eval.methods
# Conditions below exist because built_in class does not have access to `instance_methods` or `column_names`. eg: []
instance_methods = klass_eval.respond_to?(:instance_methods) ? klass_eval.instance_methods(false) : []
column_names = klass_eval.respond_to?(:column_names) ? klass_eval.column_names : []

[instance_methods, klass_methods, model_associations, column_names, active_records_methods].flatten.map(&:to_s)
end
end

def model_associations
store.transaction { |s| [s["associations"]] }
end

def active_records_methods
store.transaction { |s| [s["ar_methods"]] }
end

def exception_regexp
Expand Down
12 changes: 8 additions & 4 deletions lib/pry-byetypo/setup/dictionary/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require_relative "../store"

require "pstore"
require "zeitwerk"

module Setup
module Dictionary
Expand All @@ -25,6 +26,7 @@ def populate_store

store["active_record_models"] = populate_active_record_models_dictionary
store["associations"] = populate_associations
store["ar_methods"] = ::ActiveRecord::Base.methods
store["synced_at"] = Time.now
end
end
Expand All @@ -36,13 +38,15 @@ def establish_db_connection

def populate_active_record_models_dictionary
Zeitwerk::Loader.eager_load_all
::ActiveRecord::Base.descendants.map { |model| format_active_record_model(model) }.flatten
models.map { |model| format_active_record_model(model) }.flatten
end

def populate_associations
table_names = ::ActiveRecord::Base.connection.tables
singularize_table_names = table_names.map { |a| a.chop }
table_names.zip(singularize_table_names).flatten
models.map { |model| model.reflect_on_all_associations.map(&:name) }.flatten.uniq
end

def models
@models ||= ::ActiveRecord::Base.descendants
end

# This method takes an ActiveRecord model as an argument and formats its name and module information.
Expand Down
24 changes: 13 additions & 11 deletions spec/setup/dictionary/active_record_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
require "zeitwerk"
require "active_record"

class PostgreSQLAdapter
def tables
["users", "accounts", "deals"]
end
class TestUser < ActiveRecord::Base
has_many :deals
end

class User; end

module Account
class Deal; end
class Deal < ActiveRecord::Base
belongs_to :user
end
end

RSpec.describe Setup::Dictionary::ActiveRecord do
Expand All @@ -34,8 +32,6 @@ class Deal; end

allow(Zeitwerk::Loader).to receive(:eager_load_all)
allow(ActiveRecord::Base).to receive(:establish_connection)
allow(ActiveRecord::Base).to receive(:connection).and_return(PostgreSQLAdapter.new)
allow(ActiveRecord::Base).to receive(:descendants).and_return([User, Account::Deal])
end

context "given a staled store" do
Expand All @@ -49,13 +45,19 @@ class Deal; end
it "populates stores with associations" do
subject

expect(store.transaction { store["associations"] }).to eq(["users", "user", "accounts", "account", "deals", "deal"])
expect(store.transaction { store["associations"] }).to match_array([:deals, :user])
end

it "populates stores with ActiveRecord::Base.methods" do
subject

expect(store.transaction { store["ar_methods"] }).to match_array(::ActiveRecord::Base.methods)
end

it "populates stores with active_record_models" do
subject

expect(store.transaction { store["active_record_models"] }).to eq(["User", "Account::Deal", "Account", "Deal"])
expect(store.transaction { store["active_record_models"] }).to match_array(["TestUser", "Account::Deal", "Account", "Deal"])
end

it "populates stores with synced_at" do
Expand Down

0 comments on commit e1193d6

Please sign in to comment.