Working with Rails, Sinatra, Padrino... I got used to my code being auto-reloaded when I made modifications.
How can I get the same behavior while working on plain Ruby gem projects which are not a Rack based web framework.
I would like to just launch a pry console and inmediatly being able to test the latest modifications of my source code.
You just need to define a method somewhere that clears the old stuff from memory, and re-load all of the files that comprise your gem:
def reload!
Object.send(:remove_const, :ProjectNamespace)
path = File.expand_path("../", __FILE__)
Dir.glob("#{path}/**/*.rb") { |f| load f }
end
Since you're using Pry, you can define this in your project's .pryrc if you'd like to keep it out of your the code base.
You can even define the reload logic within your inside your module, and for as long as its included among the files you're reloading, all will be well:
module ProjectNamespace
module_function
def reload!
# Reload code
end
end
ProjectNamespace.reload!
If you're in need of a more managed solution (e.g. timed reloads) you should look into a library like Rubyworks' autoreload.
I would create a run.rb script that forks a process and runs your code in that separate process. Using https://github.com/thibaudgg/rb-fsevent in the parent process to watch your file system for changes, kill the child process whenever a FS change is detected and fork a new child with your updated code.
After some exploration and trying the given answers, I realized that I was thinking about my problem the wrong way.
Although it is nice having a project reload, this requires certain preparation.
For Ruby I find far more convenient having a custom shortcut on my editor to:
save file
send a load file/path.rb command to my Pry session
That does not require any type of extra code or configuration for each project. However the other answers can be combined with Guard to have auto-reloads. That was actually the title of my question, but now I realized that one keystroke solution is more practical.
Related
I have a web site that is killed due to a memory overflow. It is triggered during a PUT request coming from a users web browser. Unfortunately, the logs are not helpful in this case. I have traced the issue down to this method definition:
# app/controllers/registrations/profiles_controller.rb
def update
update! do |success, failure|
success.html { redirect_to edit_registration_diagnosis_path }
failure.html do
build_diagnosis
render 'edit'
end
end
end
I want to see the source code for this update! method. How do I ask ruby or rails or bash/grep to show me this source code?
I tried:
git grep 'def update!' # no results
My env:
$ rails --version
Rails 3.2.22.5
$ ruby --version
ruby 1.9.3p551
The libraries are not in the same directory as your Rails app, they'll be wherever your Ruby versions are, which differs depending on which version manager you used to install it.
The Rails docs are online at http://api.rubyonrails.org/, or you could use a gem like pry-byebug to step into the method during execution. As Ruby is object oriented and uses an inheritance chain to find an object that responds to a given message, this is the best way to really know which method is being called at any given point in the application's execution.
Add gem 'pry-byebug' to your gemfile, bundle install and then insert binding.pry at the top of your update method. Once execution pauses you can easily step into the method.
You can use byebug gem to see what is happening at each step in your method.
As others have said, the code in your app is not the full set of code that is running. So grep won't work here. You may also run into the issue where the same method is defined multiple times, and grep won't help there, either.
The best solution I've found is using pry. It looks like this is a Rails project, so you can get results most easily by adding the following to your Gemfile:
# Gemfile
gem "pry-rails"
gem "pry-doc"
At this point, the world is your oyster.
The easiest way to start learning how to use this is to add a binding.pry in your code execution where you want to explore. Then run the code in test or development environments, and your server will stop and give you a console at that line. Then you just show-source update! and you'll see where the method is defined.
So step 1, use pry and explore its many plugin libraries.
Step 2 is to try out solargraph in your text editor. It's not as powerful as pry, but it can help you jump to method definitions within your project easily. https://solargraph.org
Step 3 check out the premium text editor RubyMine, as it has support for this sort of thing and much more, though it's not free. https://www.jetbrains.com/help/ruby/getting-started.html
I have some Rails code that does not fit neatly into a model or controller box. So as per this answer, I created a app/classes directory. Rails 3 seems to automatically add this to the "load path" in Rails, and my application correctly finds the classes I define in there without needing to use require statements.
However the code in app/classes does not get reloaded in development mode; if I make a change, I need to restart the server in order to see that change.
What's the proper way to make a given directory "reloadable" in Rails 3.2.x? A few answers here recommend doing:
config.autoload_paths += %W(#{config.root}/app/classes)
but I believe that this merely has the effect of adding app/classes to the initial set of directories to find code in; does not seem to make them reloadable for each request (and furthermore in 3.x it seems that app/* is automatically added).
Update:
Figures, I stumbled upon the solution a mere 30 seconds after posting the question:
I had my class wrapped inside a module. Once I removed the surrounding "MyModule", it suddenly became reloadable. Coming from a Java background, and having been burnt by Ruby code that pollutes the global namespace, I've developed a habit of putting everything inside a module. I guess Rails "app" code must live outside of any module?
Did you declare the module in a separate file, or did you declare it implicitly inside the class? This might have an effect on autoload behavior. module Foo; class Bar vs. class Foo::Bar. It might be if the Rails autoloader can't find a foo.rb to go with the Foo module it might skip reloading it.
I just started learning Ruby coming from Java. In Java you would use packages for a bigger projects. Is there anything equivalent to that in Ruby? Or what is the best way to achieve a package like setting?
The way I'm doing it right now is 'load'ing all the needed class into my new Ruby file. Isn't there a way to tell my current Ruby class to use all other Ruby classes in the same folder?
Cheers,
Mike
There's three kinds of package loading in Ruby:
Explicitly loading a library with require
Implicitly loading a library using autoload
Importing a library with gem
The require method is the most direct and has the effect of loading in and executing that particular file. Since that file may go on to require others, as a matter of convenience, you may end up loading in quite a lot at once.
The autoload method declares a module that will be loaded if you reference a given symbol. This is a common method to avoid loading things that you don't need, but making them automatically available if you do. Most large libraries use this method of loading to avoid dumping every single class into memory at once.
The gem approach is a more formalized way of packaging up a library. Although it is uncommon for applications to be split up into one or more gems, it is possible and provides some advantages. There's no obligation to publish a gem as open-source, you can keep it private and distribute it through your own channels, either a private web site or git repository, for instance, or simply copy and install the .gem file as required.
That being said, if you want to make a library that automatically loads a bunch of things, you might take this approach:
# lib/example.rb
Dir.glob(File.expand_path('example/**/*.rb', File.dirname(__FILE__))).each do |file|
require file
end
This would load all the .rb files in lib/example when you call require 'example'.
You probably want to use require rather than load, since it should take care of circular references.
If you want to grab all the files in a given folder, that's easy enough:
Dir.foreach("lib"){|x| require x}
Your other option is to have a file that manually requires everything, and have your other files require that.
You should also look at wrapping the code in your libraries with a module block, to give them their own namespaces.
That said: rightly or wrongly, I tend to feel that this is the one area -- perhaps the only one -- where Ruby is less powerful than Python, say, or Java.
I understand your feeling. It's an ordinary problem you have to face when coming from another language like Java. I'd say try to study Ruby modules but you deserve a longer reply. So my advice is reading a good Ruby book like Eloquent Ruby.
I have only today started playing with compass and haml. While I am quite familiar with the way sass works and I get the idea of what compass is for sass and how to use it, I've hit a little bit of a road block when it comes to using haml efficiently.
Of course I am hoping that someone here already knows the answer to my problem and can give me a little jump start into haml.
Here is what I'd like to accomplish:
Auto compile my HAML files when I save them.
The project however is just a tiny static site (couple of pages) to build up a template set for a later integration into the ExpressionEngine CMS (a php based solution).
So keeping in mind that myself using HAML to simply speed up the initial "Design to HTML/CSS" process, what is a good way to auto compile my HAML files into HTML, basically something that gives me a haml watch command that I can run on my project?
Is there even something like this out there?
As for the platform I am running on, I've got a Mac running OS X 10.6.6.
Thanks for reading, any ideas, suggestions, help would be very much appreciated.
Thank you both #Jacob and #Jonathan, I ultimately ended up using neither of your approaches in favour of using middleman, hence the answer to my own question.
For those reading this topic having a similar question in mind, the reason I like middleman so much is that it effectively combines my entire workflow into 1 mini-server app.
Using mm-ini project_name and then mm-server in the directory I instantly have access to Compass, HAML and SASS all with the option of simply outputting it to plain html at any given time.
Here is more info about middleman : http://middlemanapp.com/
Staticmatic and Nanoc also do HAML but as far as I could find out they do not 'out of the box' support Compass (SASS) compilation, which for some might be an upside but for me wasn't.
Again, thanks for your answers, here is however the answer that I ultimately chose to follow.
If you have Ruby installed you could use the watchr gem.
With the help of a little nice script that I found here you can start a process that recognizes any changes to your haml file.
Beneath you can find my customized watchr.rb
def compile_haml
%x[haml index.haml index.html]
end
def do_growl(message)
growlnotify = `which growlnotify`.chomp
title = "Watchr Message"
passed = message.include?('0 failures, 0 errors')
image = passed ? "~/.watchr_images/passed.png" : "~/.watchr_images/failed.png"
severity = passed ? "-1" : "1"
options = "-w -n Watchr --image '#{File.expand_path(image)}'"
options << " -m '#{message}' '#{title}' -p #{severity}"
system %(#{growlnotify} #{options} &)
end
do_growl "Watching folders and waiting for changes..."
watch(".*\.haml$") { |x|
compile_haml
do_growl "Compiled HAML!"
}
If you do not have growl installed just leave that part away
I've found StaticMatic to be really good for building static web sites in HAML.
Maybee a bit more manual that you'd like, but you could always install the fs-events gem and do something along the lines of
require 'rb-fsevent'
require "open3"
include Open3
fsevent = FSEvent.new
fsevent.watch Dir.pwd do |directories|
puts "Detected change inside: #{directories.inspect}"
popen3('haml',
'..parameters..',
'..parameters..') do |stdin, stdout, stderr|
stdout.read.split("\n").each do |line|
puts line
end
end
end
fsevent.run
using values in the directoriesobject to call the hamlexecutable on changed files.
Although you've apparently found what you were looking for I'll still post another approach because middleman might not be the perfect solution for everyone.
My approach uses Rake. I've written a simple rakefile including a 'watch' task that recompiles my sass (or compass) and haml files whenever a file changes. Plus it reloads the browser preview :) (I don't know if middleman can do that).
The rakefile is on github: https://gist.github.com/1635301/
Codekit is what I use, it's fantastic and handles SASS, Compass, HAML, as well as many other things.
I am writing a Ruby script for use in the Rails environment, but I chose to run it from irb because reloading the Rails console can be a pain. Now the wait time is much shorter from irb, but I'm bothered that I have to restart irb and require the script everytime I make a change. Is there a simpler way of reloading a script from irb?
I found a method in this thread, but that only applies to gem files apparently. My require statement looks like this
require "#{File.expand_path(__FILE__)}/../lib/query"
EDIT: Having tried load rather than require, I still couldn't get it to work. I can't get a stop on these errors.
ruby-1.9.2-p0 > load "#{File.expand_path(__FILE__)}/../lib/query.rb"
LoadError: no such file to load -- /Users/newuser/Dropbox/Sites/rails/hacknyc/(irb)/../lib/query.rb
In irb, File.expand_path(__FILE__)} will just return "#{path you ran irb from}/(irb)". Which creates a path that doesn't actually exist. Luckily all file paths are relative to where you ran irb anyway. This means all you need is:
load "lib/query.rb"
If you want to use the __FILE__ in an actual file, that's fine, but don't expect it to produce a valid path in irb. Because an irb there is no "file" at all, so it cannot return valid path at all.
Also, __FILE__ will work fine if used in a file loaded into irb via load or require. Cause that's kinda what it's for.
Instead of using require, try load. The former only loads a source file once, while the latter loads it every time you call it.
according to this link you need to load your file and do not forget the extention.
Here is a fancier version to use too at this link number 2 which could be helpful for you too.
You may want to try hashing out why your rails console isn't working for you though.
I think load is what you are looking for.