Globally accessible function without initialisation - ruby-on-rails

Is it possible in Rails to have a "simple" function that is globally accessible?
do_something
=> "Of course"
I've tried adding an instance method to the Object class, but that adds that method to everything.

Yes. Just declare a method on Main (which is the global scope in Ruby) at any point in your application:
# config/application.rb
# ...
def do_something
end
You can reference the method explicitly with ::do_something but with the way that module nesting works in ruby any call will go up the module nesting to Main anyways.
Still is a dumb idea though as the code will not be reloaded in development and pollutes the global namespace. And since Main is on the module nesting of everything just like object you're adding a do_something method to all the objects in the system.
If you want to avoid that you would have to create a lambda/proc assigned to a global/constant:
$do_something = ->{}
DO_SOMETHING = ->{}
Or just grow up and encapsulate your method in a module/class.

Related

Using require/require_relative method in def initializer is ok?

I did not find the correct place to use the require method in any documentation. I understand that it is desirable to use the require method at the very beginning of the script, but is it possible and how correct is it to use the require method in the initializer class constructor?
Usually i make like this
require 'my_file'
how good is it to do the option below
class MyClass
def initialize
require 'my_file'
end
end
Read require method documentation
I did not find the correct place to use the require method in any documentation.
The "correct" place depends on your requirements and also on your coding style.
is it possible and how correct is it to use the require method in the initializer class constructor?
It is possible. Whether it is "correct" or not depends on your definition of "correct" and it depends on what you want to do.
require only does three things:
Search for a file in the load path.
Check whether the file was already run.
If it wasn't, run the file.
That's all require does.
If you require a file in the initializer, require will only run when you call the initializer (which is usually when you instantiate a new object).
If you need some functionality from the file before you instantiate an object, you are out of luck, since the require will not have run.
Also, you will run require every time you instantiate an object, but since require only runs the file once, that will simply be a waste of time, since it will still search for the file and check whether it was already run every time.
Lexically nesting a call to require like this can also be confusing. Someone who is not familiar with Ruby may assume that by requireing myfile inside the initialize method, the definitions inside my_file might be scoped purely to the initialize method, but that is obviously not the case: require simply runs the file, it does not perform any scoping. The definitions inside my_file will be defined wherever my_file says they are.
In the same vein, someone who is reviewing your code might assume that you think that this creates some sort of scoping and might now wonder whether your code has some sort of bug or (worse) security leak based on that assumption.
And note that "someone who is reviewing your code" might very well be yourself in two years, when you have no idea anymore why you wrote the code this way.
You can put it on top of the file before the class declaration. So you have:
require 'my_file'
class MyClass
def initialize
end
end
It's possible, it will work correctly, but it's highly unusual. I guarantee this will raise questions in code review.
Normally, requires are placed on top of the file.
Declaring the require "./file_name" is not recommended to use in the constructor method as it is often used to create the instance variable and particularly: if you are going to use an instance or global variable from that required file class as a parameter to the initialize (constructor) method of the current class, it may end up with an error.
You may use these ways to require the file at the top of the class:
require 'my_file'
class MyClass
def initialize
puts "this is a constructor"
end
end
or you may also require it just before calling your class is highly recommended to use require
class MyClass
def initialize
puts "this is a constructor"
end
end
require 'my_file'
object = MyClass.new
object.some_method
This allows you to use all the instance, class, method, object...etc.. in your current class.

How to use cattr_accessor to define config in a Rails initializer

Given the following class (this is the actual class there is no other code)
class PageRepo
cattr_accessor :root_path
end
and initializer file
PageRepo.root_path = Rails.root.join("content")
When I run
rails console
PageRepo.root_path
=> PageRepo.root_path
=> #<Pathname:/Users/blah/my_rails_app/content/pages>
However when I try to access this in my rails controller the root_path value is nil. (I've inspected this with web_console.)
No other class subclasses or is a parent of the PageRepo class and I'm not setting the root_path to nil anywhere at class level or instance level after the initializer stage. I have restarted spring and my server multiple times to no avail.
Is there something I'm not aware of when it comes to either Rails initializers or cattr_accessor?
Update
I'd like to set the path like this because throughout my code I will be initialising a PageRepo instance and the path will not change. However, it may change across different environments. I.e. in development it the path will be different than that of the test and production environments. Whilst I could just do
def initialize
#root_path = ENV['ROOT_PATH']
end
I'd prefer to not force the programmer to use ENV VARS to do this and hence my attempt above.
My solution would be just using a class method
class PageRepo
self.root_path
Rails.root.join("content")
end
end
PageRepo.root_path would return #<Pathname:/Users/blah/my_rails_app/content/pages>.
You want to have #<Pathname:/Users/blah/my_rails_app/content/pages>? or this depends on the action?
I believe your initializer is not working
an interesting post, what you are trying to achieve is writing something like this in the class initializer or constructor
class PageRepo
self.initialize
self.root_path = Rails.root.join("content")
end
end
but I never saw self.initialize being used with rails. so I believe the first approach is better.

Defining a method inside a module in ruby (NoMethodError)

I'm learning ruby, I come up on something that I don't understand. I know that modules in ruby are used for namespacing with :: (or .) and mixing with include directive.
The problem comes when I group some methods inside a module, without putting them inside a class.
Here's an example:
module Familiar
#this will not work
def ask_age
return "How old are you?"
end
#this will work
def Familiar::greeting
return "What's up?"
end
end
# this call returns **NoMethodError**
puts(Familiar::ask_age())
# this call works fine
puts(Familiar::greeting())
Why do I need to include the namespace to define the method, I'm already inside the namespace Familiar why do I have to repeat my self and put Familiar::greeting
You can test my example online following this link: http://codepad.org/VUgCVPXN
The Ruby documentation on Module answers this in its introduction text.
This form:
module Familiar
def ask_age
return "How old are you?"
end
end
defines #ask_age as an instance method on Familiar. However, you can't instantiate Modules, so you can't get to their instance methods directly; you mix them into other classes. Instance methods in modules are more or less unreachable directly.
This form, by comparison:
module Familiar
def self.ask_age
return "What's up?"
end
end
defines ::ask_age as a module function. It is directly callable, and does not appear on included classes when the module is mixed into another class.

Modifying a ruby class doesn't work as expected when running Spork

I have a plain Ruby class in my Rails app that I'm reopening in a test environment. It basically looks like
class A
def get_dependency
B
end
... some other methods ...
end
And in my test environment in cucumber (in a file loaded from features/env.rb) (and a similar place for rspec) I do
class A
def get_dependency
MockedB
end
end
This works fine in normal runs, but when I have Spork running, it fails strangely. Class A's get_dependency method is overwritten properly, but all its other public methods are now missing. Any ideas?
I'm assuming this is related to load order somehow, but I didn't get any changes when I moved the require for my file out of the preload section of Spork.
This isn't a great answer, but it's a workaround. Instead of reopening the class I just modified a singleton instance. The code is basically the same, except I added an instance method on A:
class A
def instance
##instance ||= A.new
end
end
Then in my test code I modified the instance
instance = A.instance
def instance.get_dependency
MockedB
end
And I just had to ensure that my actual code was always calling A.instance instead of A.new.
One possible scenario is that A is set to get autoloaded, but when you define the override for it in your cucumber environment, you do so before it has been autoloaded; since A now exists, it will never get autoloaded.
A possible solution, which invokes the autoloader before overriding the method is this:
A.class_exec do
def get_dependency
MockedB
end
end
It will raise a ConstMissing if A cannot be autoloaded at that point (perhaps the autoloaders have not yet been set up).

Some question about classes in plugin

I am using Ruby on Rails 3 and and I am trying to implement a new plugin. In order to learn, I am viewing inside and I am studying some popular plugins.
What I choosed is WillPaginate and in a its file there is something like this:
module WillPaginate
class << self
...
end
end
if defined? Rails
WillPaginate.enable_activerecord if defined? ActiveRecord
WillPaginate.enable_actionpack if defined? ActionController
end
I would like to know
Why the if defined? Rails statement is outside the module statement? When will be run istructions inside that?
What means and how can\should I use class << self?
module WillPaginate defines Ruby name scope and groups these methods so they can be later included with one call into some class. The if defined? Rails is outside the module because the code inside that if might include the whole module into some ActiveRecord class. And the if is executed exactly at the time when will_paginate.rb file is loaded.
All methods in that block are class methods. So later it is possible to make calls like YourModelClass.foo.
The if defined? Rails block is evaluated at load time, ie during require 'will_paginate'. That allows will_paginate to be used with or without Rails.
The class << self section is a way to define a group of methods on the WillPaginate module without having to define them all as def self.method_name. Either way works (except for a few edge cases I can't remember now), so it's mostly just a style choice.

Resources