(StackOverflow is telling me that this question is "subjective and likely to be closed"… well, I'll give it a shot regardless)
I'm writing a bunch of helper methods (for a TextMate bundle), and I'd like (and I need) to have them neatly namespaced.
These methods are really just functions, i.e. they don't operate on anything outside their own scope, and thus don't really belong in a class. There's nothing that needs instantiating.
So far, I've been doing this and that works just fine
module Helpers::Foo
module_function
def bar
# ...
end
end
Helpers::Foo.bar # this is how I'd like to call the method/function
But would it be better to:
1. Skip module_function and declare the methods/functions as self.*?
2. Or would it be better to declare a class instead of a module?
3. Or use class << self (inside a module or a class)?
4. Or something else entirely?
I realize this is a pretty open-ended question, but I'm really just looking to hear what people are doing.
I prefer either
module Foo
def self.bar
"bar"
end
end
Foo.bar #=> "bar"
or
module Foo
def Foo.bar
"bar"
end
end
Foo.bar #=> "bar"
but probably lean towards the former, i think self. is really descriptive.
Edit: After reading the comments I propose a third option that I prefer for readability. Technically I think this would be defined as extending the methods included on the Eigen class.
module Foo
module ClassMethods
def baz
"baz"
end
end
extend ClassMethods
end
Foo.baz #=> "baz"
Related
I need to monkey-patch File. Timecop doesn't affect the time that the file system reports, which is what File.atime uses and in turn that's what HttpClient uses when posting a file to a server, which in turn means VCR doesn't quite work as desired. AFAIK, this means I can't use refinements.
I don't understand what's going on here:
class File
def atime
"this one happens"
end
end
module CoreExtensions
module File
module TimecopCompat
def atime
"this one does not"
end
end
end
end
File.include CoreExtensions::File::TimecopCompat
File.new('somefile').atime # --> "this one happens"
Why does the module-based monkey patching not happen? What do I need to change for it to work? Is there a different kind of monkey-patching that I should be using?
The issue is related to the way include appends the module to the ancestor chain. "Ruby modules: Include vs Prepend vs Extend" provides a very detailed overview of the differences between include and prepend.
Take a look at these two examples:
class Foo
def hello
"1"
end
end
module Bar
def hello
"2"
end
end
Foo.include Bar
Foo.new.hello
# => "1"
Foo.ancestors
# => [Foo, Bar, Object, Kernel, BasicObject]
versus
class Foo
def hello
"1"
end
end
module Bar
def hello
"2"
end
end
Foo.prepend Bar
Foo.new.hello
# => "2"
Foo.ancestors
# => [Bar, Foo, Object, Kernel, BasicObject]
Basically, you want to use prepend in your case as include won't override the existing method.
include is not some magic thing. It is very simple actually: it makes the module the superclass of the class it is mixed into. Now: do superclass methods override subclass methods? No, of course not, it is the other way around.
Therefore, include cannot possibly override methods of the class the module is being included into.
That is what prepend is for, which mixes in a module at the beginning of the ancestors hierarchy. (Which unfortunately cannot be simply explained using inheritance, it is something different.)
Let's simplify your example without changing the question.
module TimecopCompat
def atime
"this one does not"
end
end
I have left the class File alone as it already has an instance method File#atime.
File.new('temp').atime
#=> 2019-07-16 20:20:51 -0700
As explained by the other answers, executing
File.include TimecopCompat
results in:
File.ancestors
#=> [File, TimecopCompat, IO, File::Constants, Enumerable, Object, Kernel, BasicObject]
File.new('temp').atime
#=> 2019-07-16 20:20:51 -0700
whereas executing
File.prepend TimecopCompat
results in:
File.ancestors
#=> [TimecopCompat, File, IO, File::Constants, Enumerable, Object, Kernel, BasicObject]
File.new('temp').atime
#=> "this one does not"
It is poor practice, however, to change the behavior of any core method, as its original behavior may be relied upon elsewhere in the program.
Here there are two acceptable practices. The first is to create a method (new_atime, say) that has a File object (file, say) as its argument:
file = File.new('temp')
x = new_atime(file)
new_atime cannot be chained with a File object as its receiver, but that is a small price to pay for a safe and robust solution.
The second option is to use Refinements to refine the File class.
module RefinedFile
refine File do
def atime
"this one does not"
end
end
end
class C
using RefinedFile
File.new('temp').atime
end
#=> "this one does not"
We can confirm that File#atime has not been altered outside the class C:
File.new('temp').atime
#=> 2019-07-16 20:20:51 -0700
I have following file
lib/a/b/c.rb
class a::b::c
def request(env)
#some code here
end
end
Now i am using rubocop style
Style/ClassAndModuleChildren:
Enabled: true
I am getting rubocop offense for this
lib/a/b/c.rb:1:7: C: Use nested module/class definitions instead of compact style.
class a::b::c
When i update my code to following offence get fixed
Style 1
class a
class b
class c
def request(env)
#some code here
end
end
end
end
Style 2
module a
module b
class c
def request(env)
#some code here
end
end
end
end
I think i should use Style 2 as i am using require 'a' in one of my file.
Please let me know how to fix this type & offences and reason for it
The reason this is marked as offence is that constants resolution works lexically, rather than semantically in ruby. This is not intuitive and might lead to some obscure errors (for example if you have two classes with the same name in two different scopes). Compare these two cases:
# Given
module Foo
X = 42
end
# This
module Foo
class Bar
def baz
puts X
end
end
end
# VS
class Foo::Bar
def baz
puts X
end
end
Now when you call:
Foo::Bar.new.baz
In the first case you will get 42, in the second - NameError: uninitialized constant Foo::Bar::X
As for which is the correct way to fix it: Note that using the short syntax will give you an error if Foo doesn't already exist. The answer is - you should use whatever Foo is. If it's a class - use class, if it's a module - module.
Class class is essentially derived from Module class, that’s why Class is a Module with some added functionality; basically the difference is in that Classes might be instantiated.
So, the answer to your question would be: use whatever is more suitable in your case (and by the information given it is impossible to say, what it is.)
require 'a' has nothing to do with the case, since require directive just forces ruby interpreter to load the respective code.
NB: that kind of question is the exact reason why Rubocop complains: it prevents you from using something you are not certain about and forces you to understand, is it in fact Module, or Class by it’s nature.
BTW, since you mentioned you have require 'a' somewhere, it probably means that in this a.rb you have already either module A or class A.
BTW#2 Both class and module names must begin with capital letter, because they are to be constants.
I see this popping up all the time in my code
class Foo
def initialize(foo)
#foo = foo
end
#...
end
This isn't too bad, but it gets worse:
class Foo
def initialize(foo,baz,bar,a,b,c,d)
#foo = foo
#baz = baz
#bar = bar
#etc...
You can sortof get around this by doing something like
#foo, #baz, #bar = foo, baz, bar
But even that feels wrong and is annoying to type. Is there a better way to define instance variables according to arguments?
Edit:
There seem to be 2 distinct solutions to this problem. See:
spickermann's answer
Antarr Byrd's answer
You might want to consider using a Struct:
class Foo < Struct.new(foo,baz,bar,a,b,c,d)
end
foo = Foo.new(1,2,3,4,5,6,7)
foo.bar #=> 2
No need to define an extra initialize method at all...
Yes, that's the preferred way to initialize instance variables in Ruby. It can be annoying to type, but it's a well understood pattern. As always in Ruby, using metaprogramming to automate it away is possible, but will make your code harder to follow.
I'd also argue that it's probably a good thing for a class to look ugly when it's taking more than two or three arguments. If your class depends on six different things to function, it's a strong candidate for refactoring.
def initialize args
#foo, #baz, #bar = *args
end
I think there are 3 ways to make initialization of instance variables shorter:
Use Struct or OpenStruct.
Use ruby's parallel assignment.
Use metaprogramming to make a macro like this.
The fattr gem was recently endorsed on Ruby Tapas to help solve this problem. Another consideration though, is whether there are too many things being passed into the initializer. It could be that this class is doing too much and needs to be broken into smaller pieces.
Looking for a little wisdom from fellow Rubyists. For a while now, I've used the following for convenience in some of my applications, and I'm wondering if there's a language feature I'm just missing:
class Object
def as_block
yield
end
end
There are other uses, but the normal case for me is a conditional assignment that requires a little non-trivial logic. Two obvious ways to do this:
# via a second method:
def foo
#foo ||= set_foo
end
# via conditional logic:
def foo
if #foo
#foo
else
# do complicated stuff
end
end
Both of these approaches seem kind of ugly: in the first case, #set_foo seems extraneous, and the second just looks kind of nasty. So, instead, I like this:
def foo
#foo ||= as_block do
# do complicated stuff
end
end
The problem here (aside from monkey patching Object) is that it's really a dependency (on the monkey patch) that looks like a language feature. That is, something like this really shouldn't be in (say) a Rails initializer---it seems like it should be in a gem, so the dependency can be managed correctly. Then I'm packaging an entire gem to run five lines of code to monkey patch Object...
So, my questions:
1. Anyone else use this, or something like it?
2. Has the Ruby team ever considered including something like this by default? It seems like a really easy way to use blocks as plain old expressions, but it's not there (as far as I know) which makes me wonder if there's some reason for not including it, or...
3. Is there already some better way of doing this that I'm just unaware of?
Thanks!
-E
What you're looking for is begin ... end. This isn't the same thing as a block or Proc, as it's not an object you can pass around or a closure which creates a new scope, but it should serve your purpose just fine:
def foo
#foo ||= begin
# do complicated stuff
end
end
You could use a lambda:
def foo
#foo ||= lambda do
# do complicated stuff
end.call
end
Note that it is important to call the lambda to actually execute the expression, ie
def foo
#foo ||= lambda do
# do complicated stuff
end
end
will return a lambda rather than your evaluated expression.
I'm using Ruby, and writing classes with inheritance.
For example:
class Canine
def initialize
end
def make_noise
puts "whoosh whoosh"
end
end
class Dog < Canine
def initialize
end
def make_noise
puts "wong wong"
super
end
end
Now I have a dog object:
jack = Dog.new
Is it possible to call the make_noise() method of Canine through the dog object?
In other languages it would be a typecast, something like:
(Canine)jack.make_noise
Note this is not Ruby syntax, hence, my question.
Is it possible to do this in Ruby? And if so, how?
You can do something like this:
Canine.instance_method(:make_noise).bind(jack).call
A better plan would be to just give the method in the super class an alias, or rename it.
Ruby does not allow casting or conversion in this fashion, at least not in the conventional sense. This is rarely necessary anyway, since Ruby is based on duck typing and not a rigid type system.
Are you expecting "whoosh whoosh" from the call? That's something that would only happen with non-virtual methods in a more strictly typed language like C++. It goes against proper object oriented design.
If you explore the design patterns employed in object-oriented design, you can always solve this sort of problem another way.
What you might want here is a presenter to handle the make_noise functionality.
Otherwise you'll need to write a to_canine method that can convert to the base type, though it's still not clear why you'd need such a thing.
You can do it like this:
d = Dog.new
d.class.superclass.instance_method(:make_noise).bind(d).call
or
Canine.instance_method(:make_noise).bind(d).call
. . . not pretty! I'm not sure if there's a better way
Edit: I think I agree with other answers here, in that Ruby's approach to OO will give you access to other patterns that achieve whatever goals this construct might help you with (perhaps in other languages). I don't see this kind of class/superclass method munging in practice on projects I have been involved in.
I am not sure why you need this, depending on needs it may be done totally differently, but with limited knowledge I would suggest this
class Dog < Canine
def initialize
end
def make_noise only_parent=false
puts "wong wong" if !only_parent
super
end
end
or
class Dog < Canine
def initialize
end
alias :make_super_noise :make_noise
def make_noise
puts "whoosh whoosh"
super
end
end