Fetch text string for Shoes edit box from another file - ruby

My app runs on Shoes 3 and consists of the following code
require 'somefile'
Shoes.app do
stack do
flow do
#my_editbox = edit_line
end
flow do
button "Get Name" do
#my_editbox.text = "#{#name}"
end
end
end
end
With my external file somefile.rb holding
#name = "my name"
Clicking the button does nothing, and my edit box stays empty. Any help is appreciated!

That's not how Shoes works. Shoes is not Ruby, it only looks like Ruby. Many things that you know to work in Ruby simply will not work in Shoes, because Shoes is a toolkit written in C that will work in Ruby-ish ways by directly calling the Ruby APIs.
require calls are one of the things that will not work the way you expect. There is a nicely confusing explanation about some of these rules available on the Shoes website.
Personally, I found Shoes to be so frustrating and poorly documented that it wasn't worth using even in the extremely limited ways it can be used. Good luck.
Update
You asked below about the "how". I assume you mean, how do you properly use require in a Shoes app to load code from a separate file.
Take a look at this repo for an example. You can build a normal Ruby class and then require that class in your app. You can use that class within your Shoes.app do block in a normal Ruby way. But (as far as I can tell) because of the way self changes within the block, you cannot pull in a standalone instance variable that exists outside of a class/module.
You can do something like this, though, and it does work in the way you expect:
# foo.rb
module Foo
##name = 'foobar'
end
and
# test.rb
require './foo.rb'
Shoes.app do
stack do
flow do
#my_editbox = edit_line
end
flow do
button "Get Name" do
#my_editbox.text = Foo.class_variable_get(:##name)
end
end
end
end
Here I've created a module with a class variable because it doesn't make sense to use an instance variable in something that doesn't get instantiated.
There are certainly other ways of doing this as well, and you can probably find other examples on GitHub (though you may have to tweak that query to get more results), but this is a functional example to accomplish the task you've outlined.

Related

How is called the feature that let's ruby execute code inside classes while interpreting the file

When I have the following ruby code
#file a.rb
class A
puts '2'
end
if I execute rb a.rb I get 2 printed onto the screen. This is because of the way ruby interprets the code, but, what is the name of this behavior?
The reason it prints something is because in the course of defining class A you asked it to. Anything inside a class block is treated as regular Ruby code, it's not special, so printing, exiting, making network connections, opening files, that all works as it would anywhere else.
This is in stark contrast to things like JavaScript and C++ where that is absolutely not allowed.
Ruby, being a dynamic programming language, has a lot more latitude. This permits things like defining methods based on input from files, or pretty much anything you can imagine.
The name of this behaviour is basically "evaluation", as in when Ruby evaluates that code, that is it parses and runs it.
This allows you to do things in Ruby not possible in other languages without employing macros, pre-processor tricks, or other techniques:
class A
if (Date.today.saturday? or Date.today.sunday?)
def party!
:on
end
end
end
Where that will only define the party! method when the code is run on a weekend.

Scripting in Ruby

I've developed a set of Ruby scripts. Each of them should be 'self-contained', so a user can run it on its own. But also I would like to use them to build other scripts, I mean for example to use its methods but also to run it as a whole, without doing ` script.rb`.
So far what I have is just a couple of scripts (separate files) where I have no classes, just a couple of methods. The processing of taking user input and running those methods is outside of any functions. I see that this model may be not right.
My question is, what should I do now to keep every script self contained but also to allow other scripts to use it? Should every script just contain a class with a main method that I would run object.main?
Or maybe my approach of writing a simple scripts, no classes is also good?
If I start a new script, should I always go the objective way?
When I write a one off script, I often wrap it in a class. You've pointed out some advantages of doing this including reuse and cleaner documentation.
I find that there are several levels of polish for scripts depending on how they are going to be used. If the script is run once and never used again, I may not wrap it in a class. If it's important (taking backups of production systems), it's probably worth putting it in full gem form and writing tests. Somewhere in the middle is the single purpose class. Generally this means you're taking the code that's not in a method and putting it in the class constructor.
This:
#!ruby
def amethod(i)
i+1
end
ARGF.each do |l|
if l.chomp.to_i > 0
puts amethod(l.chomp.to_i)
end
end
Becomes:
#!ruby
class OneAdder
def amethod(i)
i+1
end
def initialize
ARGF.each do |l|
if l.chomp.to_i > 0
puts amethod(l.chomp.to_i)
end
end
end
end
OneAdder.new

if __FILE__ == $0 break program when it's placed before any methods

I'm new to Ruby and am trying to understand a behavior that I've run into. I'm writing a class that needs some constants initialized before it can run, but when its run from another class, as it sometimes will be, I get warnings about constants already being defined. So I placed the following at the end of my file:
if __FILE__ == $0
constant_initialiation
ReviewScraper.new.getReviews($testing, $getWeekendReviews, $clearWorksheet, $getAll)
end
The constant_initialization is just a bunch of constants being set, nothing interesting. Anyway, this works great for me -- so long as its at the end of the file. If I move this up to the top and try running, I get an error: unitialized constant ReviewScraper (NameError). Almost as if it compiles sequentially for just this part of the file and isn't finding the ReviewScraper class definition when its run.
Can any Ruby geniuses explain this behavior to me? It's no big issue other than for styling purposes (I like having my list of constants up top), but it would be nice to understand what's going on here.
First off, I'll expand on my comments above as to what is going on. Secondly, I'll suggest perhaps a better way of setting your constants in code that avoids setting them multiple times.
As I mentioned, a Ruby script reads from top to bottom. So, if you try to instantiate a class before you define it, they the Ruby script won't know what it is.
cat = Cat.new # NameError
class Cat
# Code
end
cat = Cat.new # Works fine
The script first reads the line where you make a new Cat object. However, it doesn't know what a Cat is yet. Once it is done processing the code for what a Cat is, then it can create one. I used the example of talking to someone about Darth Vader but it is probably more akin to asking a construction company to build your building before you've ever handed them a blueprint. It is only after they have the blueprint that they can build a your building.
Now, in regards to initializing constants, there are a couple different things you could do. One is, you could put the initializations in a if block much like you did at the top but leave out the instantiating of the class until the end of the script. (Two if statements.) Another would be to put the constants in a module in its own file.
module Names
Dog = "Spot"
Cat = "Sparkles"
end
Now you just require that file wherever you need it. In file_one.rb you put
require_relative './modules/names_module.rb' # Or wherever it is
include Names
You put the same thing in your Review Scraper file. Here's the cool part: if you require the Names module once, it'll be brought into the code. However, if you require it a second time nothing will happen. You won't get warnings. It'll just quietly not require it a second time. One top of that, all your constants are in their own namespace.
Just a thought.

Structure of Ruby Programs

I need some insight into the construction of Ruby programs. I'm trying to learn how to write Ruby (independent of Rails) so I'm translating some Perl scripts I wrote in a bioinformtatics project into Ruby code. Basically creating classes where useful and whatnot.
My issue is how do I execute it? The Perl scripts are just long blocks of commands, one after the other. What's appropriate in Ruby? Should I define my classes in their own .rb files and call those and their methods in a sepearate rb file that sort of uses them to execute my program?
What is normally done? Any examples would be greatly apreciated. I'd also appreciate any tips in general on how to go about learning this kind of thing.
Ruby does have what's usually called the top level execution environment, and so a long string of commands will execute immediately just like Perl. Or, you can define classes and modules and go all OOP on your problem if you want, or you can mix the approaches.
You will need at least one line at the top level or top level of a class to start everything off. So:
p :hello
or
class A
p :hello
end
or
class A
def run
p :hello
end
end
A.new.run
or, my favorite:
class A
def run
p :hello
end
self
end.new.run
I'd highly recommend looking at some of your other favorite gems to see how their code is structured (like on Github). That's how I found my start. Thinking of your project as a "gem", being released or not, is a good way to wrap your mind around the problem.

Ruby, including module in current directory

I am currently working through the Well Grounded Rubyist. Great book so far. I am stuck on something I don't quite get with ruby. I have two files
In ModuleTester.rb
class ModuleTester
include MyFirstModule
end
mt = ModuleTester.new
mt.say_hello
In MyFirstModule.rb
module MyFirstModule
def say_hello
puts "hello"
end
end
When I run 'ruby ModuleTester.rb', I get the following message:
ModuleTester.rb:2:in <class:ModuleTester>': uninitialized constant ModuleTester::MyFirstModule (NameError)
from ModuleTester.rb:1:in'
From what I have found online, the current directory isn't in the the namespace, so it can't see the file. But, the include statement doesn't take a string to let me give the path. Since the include statement and require statements do different things, I am absolutely lost
as to how to get the include statement to recognize the module. I looked through other questions, but they all seem to be using the require statement. Any hints are greatly appreciated.
You use require to load a file, not include. :-)
First, you have to require the file containing the module you want to include. Then you can include the module.
If you're using Rails, it has some magic to automagically require the right file first. But otherwise, you have to do it yourself.
You need to require the file before you can use types defined in it. *
# my_first_module.rb
module MyFirstModule
def say_hello
puts 'hello'
end
end
Note the require at the beginning of the following:
# module_tester.rb
require 'my_first_module'
class ModuleTester
include MyFirstModule
end
mt = ModuleTester.new
mt.say_hello
The require method actually loads and executes the script specified, using the Ruby VM's load path ($: or $LOAD_PATH) to find it when the argument is not an absolute path.
The include method, on the other hand actually mixes in a Module's methods into the current class. It's closely related to extend. The Well Grounded Rubyist does a great job of covering all this, though, so I encourage you to continue plugging through it.
See the #require, #include and #extend docs for more information.
* Things work a bit differently when using Rubygems and/or Bundler, but getting into those details is likely to confuse you more than it's worth at this point.

Categories

Resources