Ruby: How to make a public static method? - ruby-on-rails

In Java I might do:
public static void doSomething();
And then I can access the method statically without making an instance:
className.doSomething();
How can I do that in Ruby? this is my class and from my understanding self. makes the method static:
class Ask
def self.make_permalink(phrase)
phrase.strip.downcase.gsub! /\ +/, '-'
end
end
But when i try to call:
Ask.make_permalink("make a slug out of this line")
I get:
undefined method `make_permalink' for Ask:Class
Why is that if i haven't declared the method to be private?

Your given example is working very well
class Ask
def self.make_permalink(phrase)
phrase.strip.downcase.gsub! /\ +/, '-'
end
end
Ask.make_permalink("make a slug out of this line")
I tried in 1.8.7 and also in 1.9.3
Do you have a typo in you original script?
All the best

There is one more syntax which is has the benefit that you can add more static methods
class TestClass
# all methods in this block are static
class << self
def first_method
# body omitted
end
def second_method_etc
# body omitted
end
end
# more typing because of the self. but much clear that the method is static
def self.first_method
# body omitted
end
def self.second_method_etc
# body omitted
end
end

Here's my copy/paste of your code into IRB. Seems to work fine.
$ irb
1.8.7 :001 > class Ask
1.8.7 :002?>
1.8.7 :003 > def self.make_permalink(phrase)
1.8.7 :004?> phrase.strip.downcase.gsub! /\ +/, '-'
1.8.7 :005?> end
1.8.7 :006?>
1.8.7 :007 > end
=> nil
1.8.7 :008 > Ask.make_permalink("make a slug out of this line")
=> "make-a-slug-out-of-this-line"
Seems to work. Test it out in your irb as well, and see what results you're getting. I'm using 1.8.7 in this example, but I also tried it in a Ruby 1.9.3 session and it worked identically.
Are you using MRI as your Ruby implementation (not that I think that should make a difference in this case)?
In irb make a call to Ask.public_methods and make sure your method name is in the list. For example:
1.8.7 :008 > Ask.public_methods
=> [:make_permalink, :allocate, :new, :superclass, :freeze, :===,
...etc, etc.]
Since you also marked this as a ruby-on-rails question, if you want to troubleshoot the actual model in your app, you can of course use the rails console: (bundle exec rails c) and verify the publicness of the method in question.

I am using ruby 1.9.3 and the program is running smoothly in my irb as well.
1.9.3-p286 :001 > class Ask
1.9.3-p286 :002?> def self.make_permalink(phrase)
1.9.3-p286 :003?> phrase.strip.downcase.gsub! /\ +/, '-'
1.9.3-p286 :004?> end
1.9.3-p286 :005?> end
=> nil
1.9.3-p286 :006 > Ask.make_permalink("make a slug out of this line")
=> "make-a-slug-out-of-this-line"
It's also working in my test script. Nothing wrong with your given code.It's fine.

Related

Why is `duplicable?` defined the way it is?

I come across this in Rails source code:
class Object
def duplicable?
true
end
end
class NilClass
begin
nil.dup
rescue TypeError
def duplicable?
false
end
end
end
With this code, even after dup is removed from an object, that object responds to duplicable? with true.
I think it can be rewritten to a simpler code like:
class Object
def duplicable?
repond_to?(:dup)
end
end
What is the merit of defining duplicable? using begin...rescue?
What is the merit of defining duplicable? using begin...rescue?
Ruby before 2.4 raised a TypeError when attempting to nil.dup:
$ rbenv local 2.3.0
$ ruby --version
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]
$ ruby -e 'p nil.dup'
-e:1:in `dup': can't dup NilClass (TypeError)
from -e:1:in `<main>'
Starting with Ruby 2.4, nil.dup just returns itself:
$ rbenv local 2.4.0
$ ruby --version
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin15]
$ ruby -e 'p nil.dup'
nil
Putting the method definition inside rescue ensures that the method is only defined for Ruby versions which raise the TypeError.
I think it can be rewritten to a simpler code like: [...]
Simply checking whether the receiver responds to dup doesn't work, because nil – being an Object – does respond to dup, even in 2.3. The TypeError is (was) raised from within Object#dup:
VALUE rb_obj_dup(VALUE obj)
{
VALUE dup;
if (rb_special_const_p(obj)) {
rb_raise(rb_eTypeError, "can't dup %s", rb_obj_classname(obj));
}
// ...
}
nil responds to dup explicitly throwing the TypeError (which has, in turn, nothing to do with NoMethodError.) [Correction: had responded to dup before 2.4, credits go to #Stefan.]
NilClass.instance_method(:dup)
#⇒ #<UnboundMethod: NilClass(Kernel)#dup>
The goal is to respond to duplicable? with false unless NilClass#dup is overwritten by another monkey patcher in the city. [Correction: read “another monkey patcher” as “Matz” :)]

Ruby 2.3 load method doesn't return classes loaded anymore - Returns boolean instead

I am migrating a project from Ruby 1.8.7 to Ruby 2.3 and rails from 2 to 4.
I have this code which was working in 1.8.7
class_list = []
original_mechanism = ActiveSupport::Dependencies.mechanism
ActiveSupport::Dependencies.mechanism = :load
begin
class_list += load("/tmp/abc.rb")
rescue Exception => e
debug e.backtrace
end
ActiveSupport::Dependencies.mechanism = original_mechanism
my sample file abc.rb
class Abc
def ...
end
class Def
...
end
In Ruby 1.8.7 class_list is [Abc,Def]
In Ruby 2.3 class_list is [true] - (I had to change the line to 'class_list << load("/tmp/abc.rb")' to make it give this output )
Any of you know how to make it return the old way? All I want is the ClassNames of the classes loaded at the end.
This is not Ruby. Ruby's load always returned true, both in 1.8.7 and 2.3.1. However, there's ActiveSupport load that uses load_dependency (http://apidock.com/rails/v3.0.0/ActiveSupport/Dependencies/Loadable/load_dependency) which does return new constants defined in the file.
Can you try to use load_dependency instead of load here?

Colors in irb / rails console

I'm testing a gem that outputs color in the terminal:
module Color
def self.colorize(text, color_code)
"#{color_code}#{text}e[0m"
end
def self.red(text)
self.colorize(text, "\033[1;31;12m")
end
end
I have a testing file in the same directory, called color_test.rb:
require_relative 'color.rb'
puts Color.red('I should be red')
This results in the following:
$ ruby color_test.rb
I should be red
And the test is actually red. Horray. However, the same is not happening in the rails console:
$ rails c
Loading development environment (Rails 4.1.1)
2.0.0-p247 :001 > require 'color'
=> true
2.0.0-p247 :003 > Chroma.colourise('text',"\033[1;31;12m")
=> "\e[1;31;12mtexte[0m"
So how do I escape it? (If that's even the term :P) I want to be able to display bold text and other styles in the console as well.
This is just for testing, so I'm okay with downloading some sort of extension for the rails console, however if there's a way to package this functionality in the gem and give the console colors, that would be pretty cool so if someone could show me how I'd be glad.
Try this:
text = 'red text'
puts "\033[31m#{text}\033[0m"
Another option is to extend String class
class String
def red
"\033[31m#{self}\033[0m"
end
def green
"\033[32m#{self}\033[0m"
end
end
Then you could do something like 'spinach'.green

How to figure out which Ruby gem has hijacked an ActiveRecord association method

Given this definition (using Rails 3.2.13 on Ruby 2.0.0-p195)...
class Food < ActiveRecord::Base
has_many :recipe_foods, foreign_key: :food_id
.reset is not acting as documented (it's supposed to reset the #loaded flag but instead it's re-querying the database and returning results)...
2.0.0-p195 :037 > f = Food.last
Food Load (1.6ms) ...
=> #<Food ...
2.0.0-p195 :038 > f.recipe_foods
RecipeFood Load (9.4ms) ...
=> [#<RecipeFood ...
2.0.0-p195 :039 > f.recipe_foods.reset
RecipeFood Load (10.0ms) ...
=> [#<RecipeFood ...
I suspect some other gem has hijacked the method, but this is what I get from .method ...
2.0.0-p195 :040 > f.recipe_foods.method(:reset).source_location
NameError: undefined method `reset' for class `Array'
How do I figure out what version of .reset is actually executing?
UPDATE:
When I try to call a non-existent method I get this chaos (in case that helps with the mystery):
2.0.0-p195 :052 > f.recipe_foods.snafu
NoMethodError: undefined method `snafu' for #<ActiveRecord::Relation:0x007fdaef6315b0>
2.0.0-p195 :053 > f.recipe_foods.method(:snafu)
NameError: undefined method `snafu' for class `Array'
My guess is that reset is actually a method on the AssociationProxy object, not the Array, which is why you're getting the undefined method. Rails 4 seems to be smarter about this:
> c = Company.first
> c.users.method(:find)
=> # <Method: ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_User(ActiveRecord::Associations::CollectionProxy)#find>
> c.users.method(:find).source_location
=> ["/Users/me/.rvm/gems/ruby-2.0.0-p195/gems/activerecord-4.0.0/lib/active_record/associations/collection_proxy.rb", 140]
I'm not sure of the best solution here, but I'd see if any of the tools in pry can be helpful.
Use a debugger. ruby-debug worked up until Ruby 1.9; byebug works for Ruby 2.0.
Write a script with a debugger breakpoint right before the call that's breaking:
f = Food.last
rf = f.recipe_foods
byebug # or debug
rf.reset
Then execute the script. The debugger will break right at before the call, which you can then step into to find out what code is actually being executed.

Emulation of each_slice without block in ruby < 1.8.7

Im trying to test my rails applications javascript using jruby 1.3.1,celerity and culerity.
The application itself runs under ruby 1.8.7 + phusion passenger (and runs fine, sans test :))
Everything installation-wise works fine but my app uses some_enumerable.each_slice(10) to split a larger array into smaller subarray with 10 elelents each.
Celerity need jruby and jruby is only ruby 1.8.6 compatible and therefor doesnt support a blockless each_slice.
So I'm thinking about defining an initalizer which adds this functionality if RUBY_PLATFORM == "java " (or RUBY_VERSION < 1.8.7)
This far I got (defunct code of cause):
if true #ruby 1.8.6
module Enumerable
alias_method :original_each_slice, :each_slice
def each_slice(count, &block)
# call original method in 1.8.6
if block_given?
original_each_slice(count, block)
else
self.enum_for(:original_each_slice, count).to_a
end
end
end
end
This code obviously is not working and I would really appreciate someone pointing me to a solution.
Thanks!
Update:
Solution thanks to sepp2k for pointing me to my errors:
if RUBY_VERSION < "1.8.7"
require 'enumerator'
module Enumerable
alias_method :original_each_slice, :each_slice
def each_slice(count, &block)
if block_given?
# call original method when used with block
original_each_slice(count, &block)
else
# no block -> emulate
self.enum_for(:original_each_slice, count)
end
end
end
end
original_each_slice(count, block) should be original_each_slice(count, &block).
Also if you leave out the to_a, you'll be closer to the behaviour of 1.8.7+, which returns an enumerator, not an array.
(Don't forget to require 'enumerator' btw)
checkout the 'backports' gem :)

Resources