I'm currently working on a fairly detailed project in Lua, specifically using LOVE2D. I'm currently using require'file' in order to access different parts of my project, but this seems like very poor form. I've ran into the problem of overwriting tables from different files with the same name. There must be a professional, cleaner way to do this, but I haven't been able to find one. Can somebody help me?
Using require is the right way to do it.
Think of a module as a function that gets executed when it's loaded. It's return value is cached and returned on subsequent require calls. Just like you would use local variables to limit the scope in a function, you can do the same in a module.
I'm guessing your modules are implemented as global tables:
mymodule = {}
function mymodule.foo()
return 'bar'
end
And you load the module like:
require 'mymodule'
Just change the module table to a local variable and return it:
local mymodule = {}
function mymodule.foo()
return 'bar'
end
return mymodule
Then, you can load the module with any name you choose:
local mymodule = require 'mymodule'
Since you don't create global variables you don't have to worry about overwriting other modules.
The example used above is from the Module Tutorial on the lua-users.org website. Check it out for more info about creating modules. Also, How to write Lua modules in a post-module() world is also worth reading.
Related
For example, to change the requiring file's environment? In my case, I'm creating a DSL (Domain Specific Language) for building behavior trees, and it would be nice if I could do something like this:
require "behaviortree"
return Sequence {
-- definition of tree
}
without polluting the global namespace with node names, or using a construct like
require "behaviortree".init()
because that's kinda ugly in my opinion. Simply placing a setfenv call in the module file's body doesn't do what I want because it would only call when I require the module the first time and not every time because of require's module caching.
I thought about clearing out the cache of the module every time I require it, but that would mean I need to do something like
require "behaviortrees"
local tree = Sequence {
-- definition of tree
}
create(tree)
and clear the module cache in the create function. That is also something I would like to avoid, but is a better option than calling an init function of the module.
Is there any 'clean' way of using a module to set the environment of the requiring file?
Write your own require function that loads the module using the "original" require and then calls the init function you need on it. Even though the "original" require returns the cached version, your own require function will still call the init function.
With the ruby CSV library with ruby on rails, you use the library by declaring require 'csv', but when using the Math module, you declare include Math. Neither library documents which declaration to use. How do you work this out, e.g. use include for module and require for a Class? If that is the case, why do you not have to require a file in the case of a module? How do you work out the file name is 'csv' and not 'CSV'?
This is not a general question about require and include but is seeking information on how to interpret the ruby-doc.org documentation to use a particular class or module.
As Jörg Mittag already pointed our in this comment: require and include are doing totally different things and have nothing in common. They aren't related to each other nor they are interchangeable.
require loads a file (reads the docs for details). Ruby doesn't magically find files or modules/classes that are defined in a file. Every piece of code that is defined in an external file requires the file to be loaded before the code is executed and can be used.
Modules in Ruby's core (like Math - note the core in the URL) are required automatically, therefore you do not need to load them yourself. But if you want to use a module or class from the standard library (like CSV) or an external gem you need to require it by yourself. This might not be obvious because tools like bundler require files for you or a gem requires internally all other files it needs.
All Ruby files need to be loaded before they can be used. require is the most common way to load Ruby files.
Imagine there is a file named foo.rb that looks like this:
puts 'loading file...'
def foo_loaded?
true
end
module Foo
def self.bar
puts 'bar'
end
end
Playing around in the console:
# `foo` wasn't required yet
> foo_loaded?
#=> NoMethodError: undefined method `foo_loaded?' for main:Object
> Foo
#=> NameError: uninitialized constant Foo
# It doesn't find the file if it ist not in the current $LOAD_PATH
require 'foo'
#=> LoadError: cannot load such file -- foo
# It loads and executes (see the output from `puts`) the file when found
> require './foo'
#=> loading file...
#=> true
# Now we can start using the methods and modules defined in the file
> foo_loaded?
#=> true
> Foo
#=> Foo
> Foo.bar
#=> bar
There is no need to include anything. Everything defined in the file is available to Ruby right away. There is not need to name give that file a special name matching the module, class or methods inside. But it is a common pattern and a good practice to name the file by its content.
include doesn't work on file-level but on the language level. It basically takes all methods from a module and includes them into another module or class. Btw: If the module you want to include is defined in an external file then you need to require that file first, otherwise Ruby won't even know that the module exists and cannot include it.
Imagine a module and class structure like this:
module Bar
def bar
puts 'bar'
end
end
class Foo
end
Foo.new.bar
#=> NoMethodError: undefined method `bar' for #<Foo:...
# Bar is not related to Foo
Foo.ancestors
#=> [Foo, Object, Kernel, BasicObject]
And when we include Bar into Foo:
module Bar
def bar
puts 'bar'
end
end
class Foo
include Bar
end
Foo.new.bar
#=> bar
# Bar is now a superclass of Foo
Foo.ancestors
#=> [Foo, Bar, Object, Kernel, BasicObject]
Things to note: There is no need to use require in this example because both the module and the class are defined in the same file. include takes the module not a string defining a file or a module name.
Because include does a very special thing it is not useful to ask: Do I need to require or include X before using it? Or: How do I know what to include? Ofter there is no need to include anything: A gem might only provide classes/modules to use directly or it might include its functionality itself. This depends on the design and the purpose of the module. You cannot tell without reading the documentation or the source code.
tl:dr
require and include do totally different things.
Ruby files must be loaded before usage. require is one way to load a Ruby file.
include includes methods from a module into the current module/class.
You must read the documentation about how to use a library, there isn't just one way to implement things.
I have foo.gem and there is lib/foo.rb in there.
When I add gem to Gemfile it's foo.rb is automatically required in my path. But I need to include it automatically. Reason for this is I am making console extension and I want them to be available without me writing `include Foo'.
I am experimenting with
SOME_CLASS.send(:include, Foo)
But not sure what class to use to have it added to the path e.g. when I start console that is automatically included. Here are some mixins automatically included in console, I need mine to be there :) Thank you
irb(main):006:0> self.class.included_modules
=> [PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Dependencies::Loadable, Kernel]
P.S.
I can solve problem with initializer but I don't want to change project's code I just want to add gem and that it works.
You should use the Kernel module, which is included by Object. It's where private methods like exit, puts and require are defined, so it is an excellent choice for defining an imperative API.
When you extend Object, people expect to be able to call your methods explicitly on any object, and they also understand that your method depends on that object's state.
Kernel methods understood differently. Even though they're technically available to all objects, you don't expect people to write things like:
'some string'.sleep 1000
This makes no sense. sleep has nothing to do with the string; it doesn't depend on it in any way. It should only be called with an implicit receiver, as if the very concept of self didn't exist.
Making your methods private and extending Kernel instead helps you get that message across.
You can do that in foo.rb:
module Foo
# …
end
Some::Class.send :include, Foo
When you load or require some file, it is executed line by line. You can put arbitrary code anywhere in the file, even inside module and class definitions. You can take advantage of that in order to properly set up your library so that others don't have to.
Did you tried
Object.send(:include,Foo)
or
self.send(:include,Foo)
inside your console
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.
Inside ActionController class (rails/actionpack/lib/action_controller.lib) I found several weird code. I don't really have a mentor to learn Ruby on Rails from, so this forum is my only hope:
Question #1: Could anyone help me explain these lines of codes?
begin
require 'active_support'
rescue LoadError
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
if File.directory?(activesupport_path)
$:.unshift activesupport_path
require 'active_support'
end
end
Especially the line with $:.unshift activesupport_path
In my thought, it tries to require active_support class, and if that doesn't work, it looks if activesupport_path is a directory, if it is, then . . . I totally lost it.
Question #2: What autoload method is for?
module ActionController
# TODO: Review explicit to see if they will automatically be handled by
# the initilizer if they are really needed.
def self.load_all!
[Base, CGIHandler, CgiRequest, Request, Response, Http::Headers, UrlRewriter, UrlWriter]
end
autoload :Base, 'action_controller/base'
autoload :Benchmarking, 'action_controller/benchmarking'
autoload :Caching, 'action_controller/caching'
autoload :Cookies, 'action_controller/cookies'
.
.
.
Question #3: If I later find a method I don't understand what for, how is the best way to find out? As for that autoload method case, I tried to find it across my project (I have my Rails code frozen there) but couldn't find any clue. I searched for "def autoload". Am I doing things wrong? Is my IDE, TextMate just doesn't cut it?
Thank you!
In order for a file to be required you have to ensure that the path to it is in the Ruby $LOAD_PATH variable. This is has a short-hand version $: for legacy reasons, inheriting this from Perl.
When you call require, the interpreter looks for a .rb file in each of the paths given there until it finds a match. If it finds one, it is loaded. If not you get an exception.
Often you will see lines like this in files:
# script/something
# This appends "script/../lib" to the $LOAD_PATH, but this expands to
# something like "/home/user/project/lib" depending on the details of
# your installation.
$: << File.expand_path(File.join('..', 'lib'), File.dirname(__FILE__))
You can use standard Array modifiers on $LOAD_PATH like unshift, push, and <<.
The first block of code is attempting to load active_support and only if that fails does it go about modifying the $LOAD_PATH to include the likely location of this file based on the path to the file making the require call. They do this because typically all gems from the Rails bundle are installed in the same base directory.
The reason for using unshift is to put that path at the highest priority, inserted at the front of the list. The << or push method adds to the end, lowest priority.
When you require a file it is loaded in, parsed, and evaluated, an operation which can take a small but measurable amount of time and will consume more memory to hold any class or method definitions inside the file, as well as any data such as string constants that may be declared. Loading in every single element of a library like ActiveRecord using require will require a considerable amount of memory, and this will import every database driver available, not just the ones that are actually used.
Ruby allows you to declare a class and a path to the file where it is defined, but with the advantage of not actually loading it in at that moment. This means that references to that class don't cause script errors in other parts of your application that make use of them.
You will often see declarations like this:
class Foo
# Declare the class Foo::Bar to be defined in foo/bar.rb
autoload(:Bar, 'foo/bar')
end
When using autoload you need to keep in mind that the class name is always defined within the scope of the module or class declaring it. In this example Bar is within Foo, or Foo::Bar using Ruby naming conventions.
When you make use of the Bar class, the foo/bar.rb file will be required. Think of it as creating a stub Bar class that transforms into the real class once it's actually exercised.
This is a great way of keeping a lot of options open, with many different modules ready to use, but without having to load everything into memory up front.
As for the third question, searchable documentation like APIDock will help you try and find more information on methods. The distinction between Ruby and Rails is often blurred, so you may have to check through both to be sure. Rails adds a lot of methods to core Ruby classes, so don't take the listing of methods available to be complete on either side. They work in conjunction.
Sometimes it pays to search for def methodname when trying to find out about where methodname originates, although this covers only conventional declarations. That method may be an alias from a mechanism like method_alias or may have been dynamically created using define_method, you can never really be sure until you dig around. At least 90% of the methods in Rails are declared the conventional way, though, so most of the time a simple search will yield what you want.