Where to define method to be accessible directly from rails console - ruby-on-rails

So idea is to define
def foo
puts "Works!"
end
and directly from the console without loading anything I write
irb(main):001:0>foo()
=> "Works!"
irb(main):002:0>
I am using 1.9.3 on Windows. I want to use this in order to have a method which will reload lib/* so that I don't need to restart the console. Thank you.

I think this is what you're asking... I have the following code in an initializer:
if defined?(Rails::Console)
require "util/console_extensions"
include ConsoleExtensions
end
and any extra methods I want in the console defined in lib/util/console_extensions.rb
module ConsoleExtensions
def foo
puts "Works!"
end
end
This automatically requires and includes the ConsoleExtension module when loading the rails console and makes the methods defined in it available without the need to manually load anything.

If this is only for testing purpose then define those files inside models :) and afterwords move them to lib directory

Related

Access Pry's show-source method from Ruby file

Is it possible to access Pry's show-source method from within a Ruby file? If so, how is this done?
For example, if I had this file:
# testing.rb
require 'pry'
def testing
puts 'hi'
end
puts show-source testing
And ran ruby testing.rb, I'd like the output:
Owner: testing.rb
Visibility: public
Number of lines: 3
def testing
puts 'hi'
end
To explain the rationale for this, I have a test stubbing a method, though the original seems to be getting called on occassion and I thought it would be handy to output the source of the call to see where it's coming from. I know there are simpler ways of doing this, though started down this rabbit hole and am interested in seeing whether this can be done :)
Running the slightly head-twisting show-source show-source shows a few methods within the Pry::Command::ShowSource class, which inherits from Pry::Command::ShowInfo.
Pry::Command::ShowSource shows three methods: options, process and content_for, though I've not been able to successfully call any.
My best assumption is the content_for method handles this, working with a code object assigned from the parent class (i.e. Pry::CodeObject.lookup(obj_name, _pry_, :super => opts[:super])), though I've not been able to crack this.
Anyone have any ideas or examples of doing this?
Ruby has the build-in method Method#source_location which can be used to find the location of the source. The method_source gem builds upon this by extracting the source based upon the source location. However this doesn't work for methods defined in the interactive console. Methods must be defined in a file.
Here is an example:
require 'set'
require 'method_source'
puts Set.method(:[]).source_location
# /home/user/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/set.rb
# 74
#=> nil
puts Set.method(:[]).source
# def self.[](*ary)
# new(ary)
# end
#=> nil
Keep in mind that all core Ruby methods are written in C and return nil as source location. 1.method(:+).source_location #=> nil The standard library is written in Ruby itself. Therefore the example above works for Set methods.
You can access source of a method without using pry with a Object#method and Method#source_location as described in this answer: https://stackoverflow.com/a/46966145/580346

Ruby gem won't add method to global scope using extend

I am trying to write a Ruby Gem which, when required, adds a function to the global scope.
I have followed the ideas here:
How can I add a method to the global scope in Ruby?, however, it just doesn't work! (on Ruby 2.4.3 anyway)
Here is my actual source code, but the below also summarises what I've done and what isn't working:
# example.rb
module Example
def self.hello()
puts "Hello"
end
end
extend Example
Then
# app.rb
require 'example' # Having built as a gem
hello() #=> `<main>': undefined method `hello' for main:Object (NoMethodError)
Where did I go wrong?
Sergio solved this for me, though I don't quite understand how!
It was considered good practice to encapsulate the methods in a module, so that users of the gem can use them directly (hello) or scoped (Example::hello) as they pleased.
By removing self. the method can be accessed directly only. By including self. it doesn't work at all. However, by doing:
module Example
extend self
def hello
puts "Hello"
end
end
extend Example
...it does work in both ways.

Ruby on Rails 4: Where i have to put Common code?

I am new to Ruby on rails. i am using rails 4.1.6 and what i want is to make log of all the process in one text file (like index page accessed, view page access etc..). for that i want to create common function, in which i can pass my text as agrs, i had do some R&D on that and i found this : In Rails, where to put useful functions for both controllers and models, but it seems that it is not working with active admin resources. so, for active admin controller and model, i have to create any other modules (i.e. on other location let say /admin/) or anything else i have to do ?
is there any global location that we can use in active admin like component in cakephp.
thanks
EDIT
app/admin/driver.rb
ActiveAdmin.register User, as: 'Driver' do
...
...
index :download_links => false do
...
...
#call function to maintain log something like,
take_note('action performed')
end
A global method feel like a code smell to me. Instead I would create a Note class or module. This doesn't pollute the global name space and is easier to test in isolation.
I would add code like this in a initializer:
# in config/initializers/note.rb
module Note
def self.take(message)
# log `message`
end
end
It could be used in your controller like this:
index :download_links => false do
# ...
Note.take('action performed')
end
Please note that you need to restart your server when changing files in the config folder.
Easiest way is to create a file in the config/initializers folder - these will be autoloaded.
You could also write it in application.rb, though I recommend only doing this for configuration.
A common pattern is to add lib/ to the autoload path so any custom files there can be used - see Auto-loading lib files in Rails 4
It's maybe worth mentioning that you can in fact access your models from anywhere as well.
for your comment
here's a generic class which you can write in lib/ if you add it to your autoload path
class MyClass
def self.my_class_method
puts "i was called"
end
end
Then calling it from anywhere else ...
MyClass.my_class_method

How to run some code only when the rails console starts, kind of like an rc file?

Is there a way to execute some code that is run only when the console starts? Kind of like an rc file (.bashrc, .zshrc, etc.)? I find myself always doing certain things a lot.
For example, where would I put this
u = User.find_by_username('my_console_user')
so that u is available in rails console?
I have resorted to this, the use of $ as global variable declaration, and the use of the obscure console do. I assume there is something more elegant somehow...
class Application < Rails::Application
#this is only executed in the console, also doens't seem to be documented anywhere but here: https://github.com/rails/rails/pull/3139
console do
$u1 = User.find_by_username('user1')
$u2 = User.find_by_username('user2')
end
end
If you use irb, just add a method in ~/.irbrc (create one if does not exist):
def find_by_username(username)
User.find_by_username('my_console_user')
end
Or add to ~/.pryrc if you use pry-rails.
Hope this helps!

override lib module method for specific rails environment

I've got a library module I'd like to override based on the rails environment I'm running in
Module is located in lib/package/my_module.rb:
module Package
module MyModule
puts "Defining original module"
def foo
puts "This is the original foo"
end
end
end
I have been able to partially solve with the info at Overriding a module method from a gem in Rails - specifically, in my environments/dev_stub.rb:
Package::MyModule.module_eval do
puts "Defining override"
def foo
puts "This is foo override"
end
end
(The other solution at that link seems to cause errors when rails tries to lookup other classes related to package)
Now, this seems to get me most of the way there, and works if I set
config.cache_classes = true
...but I want to use this as a stub development environment, and the comment recommendation on this value for a dev environment is to use false... in which case the override only works the first time the module is included, and any subsequent times, it uses the original.
My question: Am I going about this the right way? I could hack up the lib module itself to conditionally override based on RAILS_ENV, but I'd like to keep it cleaner than that...
Edit
My use case for this is to reference it from a controller function. If I have
class SomethingController < ApplicationController
def show
Package::MyModule.foo
end
end
and config.cache_classes=false (which I ideally want since it is a development environment), and access the action through my web browser (http://localhost/something/show) then the first time I hit it, my override is loaded and it works, but the second and any subsequent times, the original library class is reloaded (outputs "Defining original module" on my console without "Defining override"), and the override is lost.
Another alternative I tried was add something like config.load_paths += %W( #{RAILS_ROOT}/lib_patch/#{RAILS_ENV}) to environment.rb - but defining the same module/class didn't quite work without putting in an explicit hook in the original library to basically load the patch if it existed
Edit 2 (in response to #apneadiving answer)
I've tried doing this without module_eval, and just using the following in development_stub.rb:
require 'package/my_module'
module Package
module MyModule
puts "Defining override"
def foo
puts "This is foo override"
end
end
end
The problem I initially had with doing this is that Rails no longer automatically finds all content in my lib directory, and I need to sprinkle 'require' statements throughout all other lib files (and my controllers that reference the libs) to cover all of their dependencies. Although this is all done, it does work, but it also has a similar effect as config.cache_classes=true does, in that all the lib classes are not reloaded on change, even in my regular development environment that does not have a monkey-patch (since all the 'require' statements are added).
Setting config.cache_classes=true in dev_stub.rb and using module_eval to define the patch as described in the question seems the way to go for what the goal is here - to create an environment specific patch for a module that doesn't impact the other environments in both code path and Rails class loading behavior.
you could simply override the module and it's instance without module_eval.
I guess your module is included as a Mixin and it's methods aren't impacted by your monkey patch.
That's where alias_method_chain comes in action.
Look at this great article to get how you should use it to fit your needs.

Resources