sinatra helper in external file - sinatra

I have lot of helpers in my main Sinatra project_name.rb and I want to remove them to the external file, what is the best practice to do that ?
from ./preject_name.rb
helpers do
...#bunch of helpers
end
to for exapmple ./helpers/something.rb
thank you

The simple and recommended way:
module ApplicationHelper
# methods
end
class Main < Sinatra::Base
helpers ApplicationHelper
end

Alas, if, like me, you are building a modular Sinatra app, it's a little more complex than simply moving the helpers out into another file.
The only way I got this to work is as follows.
first up in your app (I'll call this my_modular_app.rb)
require 'sinatra/base'
require 'sinatra/some_helpers'
class MyModularApp < Sinatra::Base
helpers Sinatra::SomeHelpers
...
end
and then create the folder structure ./lib/sinatra/ and create some_helpers.rb as follows:
require 'sinatra/base'
module Sinatra
module SomeHelpers
def help_me_world
logger.debug "hello from a helper"
end
end
helpers SomeHelpers
end
doing this you can simply split all your helpers up into multiple files, affording more clarity in larger projects.

Just as you said it yourself:
Move the helpers block into another file and require it where you need.
#helpers.rb
helpers do
...
end
#project_name.rb
require 'path/to/helpers.rb'

It seems the answer #DaveSag offered miss something. Should add a line at the beginning of my_modular_app.rb:
$:.unshift File.expand_path('../lib', __FILE__) # add ./lib to $LOAD_PATH
require 'sinatra/base'
require 'sinatra/some_helpers' # this line breaks unless line 1 is added.
# more code below...
In addition, if someone prefers a "classical style" like me, the following is for you :)
In app.rb
$:.unshift File.expand_path('../lib', __FILE__)
require 'sinatra'
require 'sinatra/some_helpers'
get '/' do
hello_world
end
In lib/sinatra/some_helpers.rb
module Sinatra
module SomeHelper
def hello_world
"Hello World from Helper!!"
end
end
helpers SomeHelper
end

I just added require_relative './lib/sinatra/helpers' to my config.ru and that's all.
So it looks like this:
require_relative './config/environment'
require_relative './lib/sinatra/helpers'
use ProjectsController
run ApplicationController
and my ./lib/sinatra/helpers.rb file is not even a module and I don't use any requires or includes in it. I can just define methods straight in this file and use them all over the app.
The answer of #kgpdeveloper didn't work for me.

Related

Can I use PageObject::PageFactory without cucumber?

I am wondering if it's possible to use PageObject::PageFactory without cucumber. I tried it with
World(PageObject::PageFactory)
but there is no world without cucumber. I'm not able to find an example of another way.
Why would I do something that crazy? I want to create a gem that can downloaded by testers to use against a product that we test. I love cukes but I'd also like it to be used for exploratory testing. I've been successful doing this on the rest endpoints.
I know I can do this without PageFactory, but it's so easy that to use PageObject that way that feels like I'm cheating. I want to use these patterns.
visit(NewAccountPage)
on(NewAccountPage).create_account
Maybe there is another way entirely?
Yes, you can. There are 2 things you need to do:
Include the PageObject::PageFactory in the object that you want to use the visit, on, etc methods. (This is what Cucumber's World method is doing.)
Define a #browser variable for the Watir::Browser object.
Here is an example of using the PageFactory in the main:
require 'watir-webdriver'
require 'page-object'
# A page object
class GooglePage
include PageObject
page_url 'http://www.google.com'
end
# Including the page factory methods in the main
include PageObject::PageFactory
# Assign a browser to #browser
#browser = Watir::Browser.new :chrome
# Using the page factory
visit(GooglePage)
p on(GooglePage).current_url
#=> "https://www.google.ca/?gfe_rd=cr&ei=UxfbVdnCAaeD8QeM96CACg&gws_rd=ssl"

How to load module not in INC in Perl during runtime?

How do I load a module with a path not in the #INC in Perl?
I've read the answers on how to add a path to the #INC, but the issue is that #INC has to be changed at the beginning of the code. After it's compiled, all the modules I've come across look to #INC to find the location of the module. My issue is that we're trying to separate out all these environment specific things to a config file. If it's in a config file, the path needs to be read before it can be pushed to #INC, but then the code has already been compiled and it seems #INC can't be modified.
Is there a way? Is there a library that lets me load a module and pass it a custom path?
Is this a terrible bad thing to do? Why?
Perl has an incremental compilation model which means that code can be executed before other code is even parsed. For this, we can use phase blocks (aka. phasers):
BEGIN {
print "This is executed as soon as the block has been parsed\n";
}
Such a phase block could also be used to load a configuration file.
For example, use statements are effectively syntactic sugar for a BEGIN block.
use Foo::Bar qw/baz qux/;
is equivalent to
BEGIN {
require Foo::Bar; # or: require "Foo/Bar.pm";
Foo::Bar->import(qw/baz qux/);
}
We can also load modules at runtime, although that's only sensible for object-oriented modules.
So we have three options:
Load config in the BEGIN phase and add the correct library paths before loading the actual modules
Load the modules manually during BEGIN with their full path (e.g. require "/my/modules/Foo/Bar.pm"
Figure out the configuration at runtime, load modules after that.
Using bare require is fairly uncomfortable, which is why Module::Runtime exists
Use a BEGIN block to load your custom #INC location and then use lib to include it.
# use lib /a special directory/
BEGIN {
my $lib_to_include = ...;
require lib;
lib->import($lib_to_include);
}
use Module_That_Requires_Special_Dir;
The only thing to note is that whatever code you use to load your custom include directory will have to rely on methods already defined before this BEGIN block. Therefore you can't use a subroutine that is later in the file.
Came across only, which seems to let a path be passed to the use argument like so:
use only { versionlib => '/home/ingy/modules' },
MyModule => 0.33;
It has to be used with a version condition, but putting this here anyways since it's relevant to my question 1 and I wasn't able to find any modules first time around that allowed a path outside #INC.
require supposedly is able to take in a full path, according to the perlfaq with
require "$ENV{HOME}/lib/Foo.pm"; # no #INC searching!

Using erb template and sidekiq

I'm using sinatra and sidekiq together. I'm trying to render a erb template from within a sidekiq worker and i'm getting a undefined method 'erb'. In my head, things should work cause sidekiq is loaded up as an instance of my sinatra app, so it should have the erb method. What am i missing here?
class SomeWorker
include Sidekiq::Worker
def perform(id)
erb(:emailTemplate)
end
end
(i now realized the SomeWorker class has nothing to to do with sinatra and so of course it doesn't have the erb method. maybe i can just make a call out to helper module? in place of the erb method call?)
so i figured out 1 solution:
require 'erb'
require 'tilt'
class ForgotEmailWorker
include Sidekiq::Worker
def perform
template = tilt.new(__path_to_erb_file).render
end
end

Prevent multiple inclusions in perl

Suppose I have two files: a module file that looks like this:
package myPackage;
use Bio::Seq;
and another file that looks like this:
use lib "path/to/lib";
use myPackage;
use Bio::Seq;
How can i prevent that Bio::Seq is included twice? Thanx
It won't be included twice. use semantics could be described like that:
require the module
call module's import
As the documentation says, it's equivalent to:
BEGIN { require Module; Module−>import( LIST ); }
require mechanism, on the other hand, assures modules' code is compiled and executed only once, the first time some require it. This mechanism is based on the special variable %INC. You can find further details in the documentation for use, require, and in the perlmod page.
use Foo
is mostly equivalent to
# perldoc -f use
BEGIN {
require "Foo.pm";
Foo->import();
}
And require "Foo" is mostly equivalent to
# perldoc -f require
sub require {
my ($filename) = #_;
if (exists $INC{$filename}) {
return 1 if $INC{$filename};
die "Compilation failed in require";
}
# .... find $filename in #INC
# really load
return do $realfilename;
}
So
No, the code won't be "Loaded" more than once, only "imported" more than once.
If you have code such as
package Bio::Seq;
...
sub import {
# fancy stuff
}
And you wanted to make sure a library was loaded, but not call import on it,
#perldoc -f use
use Bio::Seq ();
Modules aren't "included" in Perl like they are in C. They are "loaded", by which I mean "executed".
A module will only be loaded/executed once, no matter how many use statements specify it.
The only thing that happens for every use of a module is the call to the module's import method. That is typically used to export symbols to the using namespace.
I guess, you want to optimize the loading(usage) of Module.
For optimizing, dynamic loading may be helpful.
For dynamically loading a Perl Module, we use Class::Autouse.
For more details you can visit this link.
I guess the OP may look for a way of avoiding a long list of use statement boilerplate at the beginning of his/her Perl script. In this case, I'd like to point everyone to Import::Into. It works like the keyword import in Java and Python. Also, this blog post provides a wonderful demo of Import::Into.

Alias a Package to Enable Dual Use Namespaces

I have an interesting situation. In some (large) legacy code, there is a namespace that should look like require A::B, but instead the path to A was added so it's possible to just say require B. However, I would like to be able to use both invocations. Is this possible without creating a redirecting package? For instance, is there a way to dual declare a package?
Thanks!
First load the package:
require A::B;
Then alias B to A::B:
*B:: = *A::B::;
Then tell require that it has already loaded B
$INC{'B.pm'}++;
To make sure this all works right, it is best to perform these actions inside a BEGIN block:
BEGIN {
require A::B;
*B:: = *A::B::;
$INC{'B.pm'}++;
}
After this, all require A::B; and require B; lines will become no-ops. You will also be able to refer to variables in that package with either name. \&A::B::foo == \&B::foo
To get this to work transparently, you could add the following code to each file:
A/B.pm
*B:: = *A::B::;
$INC{'B.pm'}++;
B.pm
*A::B:: = *B::;
$INC{'A/B.pm'}++;
Then if a user does require A::B; they can call A::B::foo or B::foo and require B; will become a no-op.
And if a user does require B; they can call A::B::foo or B::foo and require A::B; will become a no-op.
But for maintainability, it is probably best to keep all of the real code in one file (along with the aliasing code above), and setup the other file as a shim that just loads the real file. Assuming A/B.pm contains the real code:
A/B.pm
*B:: = *A::B::; # this gets added to the existing file
$INC{'B.pm'}++;
B.pm
require A::B; # this is the entire file
require Something will search the directories in #INC for a file called Something.pm.
To get some-path/A/B.pm to be loaded with either require B or require A::B, you would need to have both some-path and some-path/A in your #INC directory list.
There are many many ways to add directories or otherwise manipulate your #INC list.
Eric's solution would work, but truthfully, I'd shoot anyone who did this in real production code. You could probably achieve similar results by using methods in Package::Stash, but again, why mess up the symbol table like this? I'd rather fix the legacy code that was calling things the wrong way. Seriously, how hard is it to do a search-and-replace on your code and fix the package names?
Another quick and dirty method to get require B; to actually find package A::B is to simply make a symlink in the lib/ directory pointing to A/B.pm:
cd lib
ln -sf -T A/B.pm B.pm
Note that this will create two packages with identical code, so variables in one will not be the same value as the other: $A::B::foo will be entirely separate from $B::foo even though their declaration comes from the same file.