Utility Classes In Ruby on Rails - ruby

This is probably a stupid question, but I'm new to Ruby on Rails and I could use a little guidance. I want to have a helper/utility class that performs a group of network operations and returns results. Where do I put that class and how do I use it.
I've created network_helper.rb in my app/modulename/helpers directory. In my controller when I try to do
myNetworkHelper = ModuleName::NetworkHelper.new
results = myNetworkHelper.getResults
I get an error
undefined method `new' for MyModule::NetworkHelper:Module
I'm sure this is just a misunderstanding of how ruby on rails works. Can I get some clarification?
Would it be better to make this a class instead of a module and put it in libs? And can I add subfolders in libs and have them automatically loaded?

Lib or Classes
Little utility classes like this typically go in the lib folder, though some people prefer to create a folder called classes. Whichever you choose, make sure you import the folder in config/application.rb, as the lib folder is not autoloaded:
config.autoload_paths += %W(#{config.root}/lib)
Concerns
If instead of a utility class, you want to extend some of your models with reusable code, you may also wish to look at the new Rails 4 concerns folders which encourage you to extract reusable modules:
see: How to use concerns in Rails 4

To use new, the thing your calling it on must be a class, not a module. You're using a module. Change module to class in lib/utilities/network_utility.rb.

I cannot verify this at the moment, however I believe one place you can store your custom modules and classes is the lib directory. Alternatively, you should be able to store them in the app directory in the manner you have indicated by adding the following line to your environment.rb:
config.load_paths << File.join(Rails.root, "app", "modulename")
Also, check out Yehuda Katz's answer, which I think not only answers your question better, but also contains some very interesting and useful information and concepts relating to your situation. Hope that helps!

Add your class to app/lib folder instead of lib, so that you don't change autoload paths!
Explanations:
The accepted answer suggests adding the classes to lib.
But according to this discussion:
The lib folder does not belong to the autoload paths since Rails 3.
So it's discouraged to add lib under autoload path. Use app/lib instead.

Related

Can I extend the core helpers within a package in Code Igniter?

I'm building my own base to use on multiple sites that I will be building. And I've made a package for that. But I want to extend the CI helpers in that package (not in the app) - helpers such as url_helper, html_helper etc.
I've put a config folder (although I don't really understant what it does) in the package folder and a config file in it (so structure is packages/app_package/config/config.php).
I've put the $config['subclass_prefix'] = 'app_'; (different from the application one preferably) and still not loading the helpers app_url_helper etc
Did anybody do that?
Have a look at CodeIgniter Helpers. Specifically the section labelled "Extending" Helpers.
I'm not quite sure what you mean by:
I've put a config folder (although I don't really understant what it
does) in the package folder and a config file in it (so structure is
packages/app_package/config/config.php).
You're not required to 'create' any config folders or files at all. The config file already exists and is located in application/config/config.php of your CodeIgniter project. The Class Extension Prefix is located ~ line 110 (version dependent). Set it to _app
Now create app_url_helper.php and app_html_helper.php in application/helpers and away you go.

How to work with classes and dependences in ruby

I have changed this question to better reflect what it is I do not understand.
For example if I try to access the methods in the railties class AppBuilder.
require 'rails/generators/rails/app/app_generator'
g = Rails::AppBuilder.new
puts g.rakefile.inspect
I get an error message activesupport-3.1.3/lib/active_support/secure_random.rb:5:in `': uninitialized constant SecureRandom (NameError)
I do not understand this. Should not each class be "independent" from other classes? Is that not the whole point of object oriented programing?
And now If it is not so more importantly how can I figure out what dependences I need to add? Is it some kind of workflow to solve this? Can I somehow figure out what dependencies to add looking at the documentation? Do this problem have something to do with load path? Can I load all dependences from a gem or rails or whatever? I just don't get it!
doc: http://api.rubyonrails.org/classes/Rails/AppBuilder.html github: https://gist.github.com/rails/rails/blob/master/railties/lib/rails/generators/rails/app/app_generator.rb
there is no easy way to find out which dependencies are used within AppBuilder, cause most of the dependencies are setup somewhere else. so most of the times you need to do some trial and error to get the dependencies right.
the code that you posted has bad style. please get familiar with how to write ruby code properly. buy yourself a book i.e. eloquent ruby or just start reading ruby blogs.
dependencies in ruby is quite simple. every file that you require will be loaded and the load will recurse through the files and then load other requires. the loading will only work if all the required files are on the load path. this load path is similar to your system path and you can add directories to it to tell ruby where to look for files.
in general, there are dedicated entry-points for libraries and their dependencies. those are normally documented, so that if you use them, you get all dependencies right from the beginning. an example for this would be to require 'rails' in order to use rails or require 'active_support/all' if you just want to use active-support. if you wan't to chery-pick files/classes than you are on your own finding out which other classes you need. that part has nothing to do with oop, it's more an dependency-issue (other languages have explicit decleration of dependencies).
in your case, the next step would be to add require "securerandom" to the beginning of your file and then check wich error comes up next.

How can I build a modular command-line interface using rubygems?

I've written a command-line tool for manipulating with genome scaffolds called "Scaffolder". At the moment all the tools I want to use are hard-coded into the library. For instance these tools "validate" or "build" the scaffold. I'd like to split these tools out into their own gems, make it more modular, and to allow third parties to write their own commands.
The ideal case would be that I run "gem install scaffolder-validate" and this gem-bundled command would then be available as part of scaffolder. I know a couple of libraries make it easy to build a command-line interface: thor, commander, gli, .... However I don't think any of them cater for this type of functionality.
My question is how can I use a gem structure to create a module structure for installing these commands? Specifically how can the installed commands be auto-detected and loaded? With some prefix in the gem name scaffolder-* then searching rubygems? How could I test this with cucumber?
So, one thing you can do is to decide on a canonical name for your plugins, and then use that convention to load things dynamically.
It looks like your code is all under a module Scaffolder, so you can create plugins following the following rules:
Scaffolder gems must be named scaffold-tools-plugin-pluginname
All plugins expose one class, named Scaffolder::Plugin::Pluginname
That class must conform to some interface you document, and possibly provide a base class for
Given that, you can then accept a command-line argument of the plugins to load (assuming OptionParser):
plugin_names = []
opts.on('--plugins PLUGINS','List of plugins') do |plug|
plugin_names << plug
end
Then:
plugin_classes = []
plugin_names.each do |plugin_name|
require "scaffold-tools-plugin-#{plugin_name}"
plugin_classes << Kernel.const_get("Scaffold::Plugin::#{plugin_name}")
end
Now plugin_classes is an Array of the class objects for the plugins configured. Supposing they all conform to some common constructor and some common methods:
plugin_classes.each do |plugin_class|
plugin = plugin_class.new(args)
plugin.do_its_thing(other,args)
end
Obviously, when doing a lot of dynamic class loading like this, you need to be careful and trust the code that you are running. I'm assuming for such a small domain, it won't be a concern, but just be wary of requireing random code.
Hm, tricky one. One simple idea I have is that the main gem just tries to require all the others and catches the load error when they are not there and disables the respective features. I do this in one of my gems. If HighLine is present, the user gets prompted for a password, if it isn't there has to be a config file.
begin
require 'highline'
rescue LoadError
highline = false
end
If you have a lot of gems this could become ugly though...

Joomla two module using same helper.php

I've built two custom modules for Joomla ("reservation" and "contact") which are working just fine, however time to time I have to upgrade them.
Is it possible to make them to share the same "helper.php" so I could keep code in one place? For example the post function is the same for these two modules. I want the "contact" module to use the "reservation" helper.php post function.
Thanks
You can simply include the reservation module helper inside the contact module and use it.
For example lets say that your modules are mod_reservation and mod_contact, in mod_contact.php you include the reservation helper file and use it like this:
require_once JPATH_SITE.DS."modules".DS."mod_reservation".DS."helper.php";
modReservationHelper::post();
Or you make a custom helper module,, which is needed in order for the other 2 to work. I dont know for sure but I thought you can check for other modules when installing a module. In that check you check for the helper module and if not present you give a error. You could also say that a certain module needs atleast version X.XX.XX of the helper module and if the version is too long also give an error in during the install of the module.

PHP: Only include files when running phing?

I have the following folder structure:
/main
/loader.php
/build.xml
/components
/package1
/class1.php
/package2
/class2.php
/tests
/package1
/class1.test.php
/package2
/class2.test.php
When I run the web application I load loader.php at first and include other components by calling Loader::load( 'package_name' ). Then all neccessary files are included. The good thing here is that I don't need to include loader.php within the class files because I can rely on having a working instance of Loader.
The Unit Test classes simulate this behaviour by including all neccessary classes explicitly. So there is also no problem with phing and PHPUnit.
But now I want to generate a coverage report with phing and Xdebug. The problem here is that phing seems to load every single PHP file to create the coverage database. Unfortunately it stops because it cannot find the Loader class that is used in the PHP files.
I could easily add an include statement to every class file, but I wonder whether there is a way to include files only if code coverage analysis is inspecting the file?
Other idea: I could also configure the coverage analysis in a way that it scans the unit tests directory and therefore finds all neccessary includes. Then I'd need to filter classes that match to a pattern like /Test$/i or so. Possible?
I looked for ages for something similar.
In the end I ended up with the changes below. Basically you tell php cli to prepend a php file which contains your loading logic.
In php.ini of my cli I've set the following:
auto_prepend_file = autoload.php
I made sure that the file was on my include path (/usr/share/php in my case) and put following lines in it (I use Zend Framework which is also on my include path):
require_once "Zend/Loader/Autoloader.php";
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('Model_');
Now, what you could do is define your __autoload function and define what needs to be autoloaded, but you get the idea.
It's an ugly hack, but it got things done for me.
Wkr
Jeroen

Resources