Pass input parameters to ruby-written shell? - ruby

I'm trying to write a shell in Ruby (using readline), implementing some custom commands. To create the correspondence between given input and methods that are defined in an external module I'm using an hash like this
hash = {
'command_1' => method(:method_1),
'command_2' => method(:method_2)
}
And once I got the user input I pass it to the hash calling the method associated with the command-key
hash[input.to_s].()
My questions are: how can I handle variants of the same command? (e.g. for the help command give different output depending if a flag is given, something like help -command_1)
How can I pass parameters to methods in the hash? (e.g. pass to an open command the file to be opened like open file_name)
Thanks to all in advance.

While that might work if you wrangle it enough, the easy way is this:
hash = {
'command_1' => :method_1,
'command_2' => :method_2
}
send(hash[input.to_s])
The send method allows dynamic dispatch which is way easier than trying to deal with method.

Related

ruby: howto use multiple boolean options and keep the code readable

I need to process a couple of boolean options, and I am trying to do it like it is usually done in C:
DICT = 0x000020000
FILTER = 0x000040000
HIGH = 0x000080000
KEEP = 0x000100000
NEXT = 0x000200000
I can now assign arbitrary options to a Integer variable, and test for them:
action if (opts & HIGH|KEEP) != 0
But this looks ugly and gets hard to read. I would prefer writing it like
action if opts.have HIGH|KEEP
This would require to load have method onto Integer class.
The question now is: where would I do that, in order to keep this method contained to the module where those options are used and the classes that include this module? I don't think it's a good idea to add it globally, as somebody might define another have somewhere.
Or, are there better approaches, for the general task or for the given use-case? Adding a separate Options class looks like overkill - or should I?
You can use anybits?:
action if opts.anybits?(HIGH|KEEP)
The methods returns true if any bits from the given mask are set in the receiver, and false otherwise.

Running unix shell TalendJob

I have a issue. I build myTalendJob and I am running myShell succesfully by adding a contextVariable. The command I use is:
./mainJob_run.sh --context_param myVar="/myDirectory/file.txt"
Is it possible to simply run ./mainJob_run.sh and passing dynamically --context_param myVar="/myDirectory/file.txt" avoiding to rewrite it anytime?
Thank you in advance!
I am not sure I understand your question but this is my attempt to answer.
Either:
When exporting your job, override the context "myVar" by this given value
Write caller script to call mainJob_run.sh appending this additional parameter. I prefer this one as it gives more flexibility
Implicit contexts load
You can read your context params from a file.
With this, you don't need to pass the context params through the shell command, but instead it reads the context params from a file when the job is executing.Ideally, you should put this in your tPreJob.
After reading the values, you can also pass the context params through a tJavaRow for further processing. This way you can format your context params, or generate new context params based on the input values.
TalendByExample has provided a great guide on how to build a reusable context loading job which you can call from any of your jobs.
https://www.talendbyexample.com/talend-reusable-context-load-job.html

Split array into comma separated list of values

I'm working on a bit of metaprogramming using send methods quite a bit. I've been successful so far because the methods I'm sending to only take one argument.
Example:
client is an API client
#command is a method on client taken as an option to a CLI utility
#verb is a method on command taken as another option in the CLI
def command_keys
case #command
when "something"
self.command_options.slice(:some, :keys)
end
end
Then I call the API client like this:
client.send(#command).send(#verb, command_keys)
This works since the methods all take a Hash as their argument. The problem I've run into is when I need to send more than 1 parameter in command_keys. What I'm wondering is the best way to handle the command_keys method returning more than 1 value. Example:
def command_keys
case #command
when "something"
return self.command_options[:some], self.command_options[:keys]
end
end
In this case, command_keys returns an Array as expected, but when I try to pass that in the send(#verb, command_options) call, it passes it as an Array (which is obviously expected). So, to make a long story short, is there some easy way to make this condition be handled easily?
I know send(#verb, argument1, argument2) would get me the result I want, but I would like to be able to not have to give my script any more implementation logic than it needs, that is to say I would like it to remain as abstracted as possible.
Use splat. You might have to rethink the code a bit, but something like:
client.send(#command).send(#verb, *all_the_args)

PageObject with Ruby - set text in a text field only works in the main file

I'm automating a site that has a page with a list of options selected by a radio button. When selecting one of the radios, a text field and a select list are presented.
I created a file (test_contracting.rb) that is the one through which I execute the test (ruby test_contracting.rb) and some other classes to represent my page.
On my class ContractPage, I have the following element declaration:
checkbox(:option_sub_domain, :id => "option_sub_domain")
text_field(:domain, :id => "domain_text")
select_list(:tld, :id => "domain_tld")
I've created in the ContractPage a method that sets the configuration of the domain like this:
def configure_domain(config={})
check_option_sub_domain
domain = config[:domain]
tld = config[:tld]
end
When I call the method configure_domain from the test_contracting.rb, it selects the radio button, but it doesn't fill the field with the values. The params are getting into the method correctly. I've checked it using "puts". Even if I change the params to a general string like "bla" it doesnt work. The annoying point is that if on test_contracting.rb I call the exact same components, it works.
my_page_instance = ContractPage.new(browser)
my_page_instance.domain = "bla"
my_page_instance.tld = ".com"
What I found to work was to in the configure_domain method, implement the following:
domain_element.value = config[:domain]
tld_element.send_keys config[:locaweb_domain]
Then it worked.
The documentation for the PageObjects module that I'm using as reference can be found here: http://rubydoc.info/github/cheezy/page-object/master/PageObject/Accessors#select_list-instance_method
Do you guys have any explation on why the method auto generated by the pageobject to set the value of the object didnt work in this scope/context ?
By the way, a friend tried the same thing with Java and it failed as well.
In ruby all equals methods (methods that end with the = sign) need to have a receiver. Let me show you some code that will demonstrate why. Here is the code that sets a local variable to a value:
domain = "blah"
and here is the code that calls the domain= method:
domain = "blah"
In order for ruby to know that you are calling a method instead of setting a local variable you need to add a receiver. Simply change your method above to this and it will work:
def configure_domain(config={})
check_option_sub_domain
self.domain = config[:domain]
self.tld = config[:tld]
end
I'm pretty new to this world of Selenium and page objects but maybe one of my very recent discoveries might help you.
I found that that assignment methods for the select_list fields only worked for me once I started using "self" in front. This is what I have used to access it within my page object code. e.g., self.my_select_list="my select list value"
Another note - The send_keys workaround you mention is clever and might do the trick for a number of uses, but in my case the select list values are variable and may have several options starting with the same letter.
I hope something in here is useful to you.
UPDATE (Jan 3/12)
On diving further into the actual Ruby code for the page object I discovered that the select_list set is also using send_keys, so in actuality I still have the same limitation here as the one I noted using the send_keys workaround directly. sigh So much to learn, so little time!

Trouble creating custom routes in Ruby on Rails 3.1

I can't seem to set up a custom URL. All the RESTful routes work fine, but I can't figure out how to simply add /:unique_url to the existing routes, which I create in the model (a simple 4 character random string) and will serve as the "permalink" of sorts.
Routes.rb
resources :treks
match ':unique_url' => 'treks#mobile'
Controller
.
.
def mobile
#trek = trek.find(params[:id])
end
Is this because I'm trying to define a custom action on an existing resource? Can I not create custom methods on the same controller as one with a resource?
By the way, when I change routes.rb to match 'treks/:id/:unique_url' => treks#mobile it works fine, but I just want the url to simply be /:unique_url
Update It seems like find_by_[parameter] is the way to go...
I've been playing in console and I can't seem to get any methods to come forward...I can run Trek.last.fullname for example, but cannot run #trek = Trek.last...and then call...#trek.lastname for example. Any clues why? I think this is my issue.
So is there a field on Trek which stores its unique url? If so you should be doing something like this:
#trek = Trek.find_by_url(params[:unique_url])
trek.find_by_unique_url( params[:unique_url] ) # should do the trick
#pruett no, the find_by_XXX methods are generated on-the-fly via Ruby's method_missing call! So instead of XXX you can use any of the attributes which you defined in a model.
You can even go as far as listing multiple attributes, such as:
find_by_name_and_unique_url( the_name, the_unigue_url)
Check these pages:
http://guides.rubyonrails.org/active_record_querying.html
http://m.onkey.org/active-record-query-interface
if you get a undefined method ... for nil:NilClass , it means that the object you are trying to call that method on does not exist, e.g. is nil.
You probably just missed to put an if-statement before that line to make sure the object is non-nil
Hmm. I usually would do something like this:
map.connect "/:unique_url", :controller => "treks", :action => "mobile"
Then in that controller the ID isn't going to be applicable.. you'd need to change it to something like this:
def mobile
#trek = trek.find_by_unique_url(params[:unique_url])
end
(that's if unique_url is the column to search under)

Resources