I would like to make a DSL in Ruby, where I will can using simple commands do something. For example "GO PRINT 10 *" will print 10 stars
or "GO PRINT 5 &" will print 5 ampersand. Anyone know good tutorials ?
I heard about the gem docile It is worthy of attention?
Here are some links relevant to what you want to do:
https://robots.thoughtbot.com/writing-a-domain-specific-language-in-ruby
Tutorials for writing DSL in Ruby
https://www.leighhalliday.com/creating-ruby-dsl
If you want a very flexible DSL (i.e., one in which you can't tell that it's actually Ruby, which sounds like what you want), I'd suggest learning a language such as Racket which is very well-geared towards creating all sorts of languages, e.g., a brainf*ck clone, a stack-based calculator, these, and these.
This problem is to get into an internship within a devops department:
"Write a ruby library that executes arbitrary system calls (eg: “dmesg", "ping -c 1 www.google.com”) and provides separated output streams of stderr and stdout as well are providing the final return code of the process. Show your work with unit tests.”
Am I supposed to use already established system calls and replicate them in Ruby code? That seems silly to me. Am I supposed to come up with my own arbitrary calls and write a library complete with errors and status calls?
I am not looking for someone to write this for me. I feel that the first step to solving this problem is understanding it.
Get Clarification from the Source
The assignment is poorly worded, and misuses a number of terms. In addition, we can only guess what they really expect; the appropriate thing to do would be to ask the company directly for clarification.
Re-Implement Open3
With that said, what they probably want is a way to process any given command and its arguments as a decorated method, akin to the way Open3#capture3 from the standard library works. That means the code you write should take the command and any arguments as parameters.
For example, using Open3#capture3 from the standard library:
require 'open3'
def command_wrapper cmd, *args
stdout_str, stderr_str, status = Open3.capture3 "#{cmd} #{args.join ' '}"
end
command_wrapper "/bin/echo", "-n", "foo", "bar", "baz"
#=> ["foo bar baz", "", #<Process::Status: pid 31661 exit 0>]
I sincerely doubt that it's useful to re-implement this library, but that certainly seems like what they're asking you to do. Shrug.
You're also supposed to write unit tests for the re-implementation, so you will have to swot something up with a built-in framework like Test::Unit or MiniTest, or an external testing framework like RSpec, or Wrong. See the Ruby Toolbox for a more comprehensive list of available unit testing frameworks.
Luckily for you, Ruby makes it very easy to interact with the underlying operative system.
You can start by reading the documentation for these methods:
Kernel#`
Kernel#system
Kernel#exec
Kernel#spawn
IO#popen
Also, there is the Open3 module from the stdlib.
I am a fairly new to programming (3 months in), and am attempting to learn via TDD.
Obviously the point to TDD is write the test cases first, this particular piece I wasn't sure how to.
The code snippet is:
class PhraseFactory
def initialize
#sentence = ''
end
def make_sentences_from
for i in 0 ... self.length
#sentence += self[i] + ' '
end
end
How I was thinking to test it was using:
describe "When sent a message(<< is that proper terminology?) from an array of strings"
it "Builds a sentence"
my_word_array.should_have (here is where I am unclear)sent_a_message_to(make_sentences_from)
Thanks for any help.
i like TDD but i would not recommend anyone to use TDD to learn something new! it's always a good idea to use the REPL (irb) to experiment with code.
your example is full of WTFs for any ruby developer:
you are missing all the ENDs (looks kinda like python?!)
you are naming something Factory (are you a java guy?)
you use for instead of each
you are doing stuff in a class that should be a oneliner
you reinvent the wheel by rebuilding core functionality
besides that, i don't really understand your question and code...
what should the result of your code be? what is the input to your "factory"
$ irb
> %(you can just use join to build a sentence from an array of words).join
"you can just use join to build a sentence from an array of words"
Learning both a new language (Ruby) and technique (TDD) at once may be a bit too much. On the other hand, I find unit tests a great way to clarify code behavior, and as such a good learning tool. One suggestion here would be to look into something like the Ruby Koans: http://rubykoans.com/
I am not a Rubyist, so I can't comment on their quality, but I used the F# Koans, which were adapted from the Ruby ones, and were pretty good. This should both give you a good entry point into the language, as well as a familiarity with unit testing, which should serve you well once you start working on your own project and get into TDD.
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.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I was having a discussion with some programmer friends who said that they see Ruby programmers (in particular) producing a lot of code that's "too clever". So I'm wondering what would that look like? I'm referring to the unnecessary use of an obscure language feature in a context in which something straightforward would have worked just as well or better. Know any good Ruby examples of this?
After giving a straight answer to your question, I'd like to also dispute the premise; whenever a group of programmers characterizes the users of another language in this way, the odds are that they are telling you more about themselves than about the community they are describing.
You could, for example, accuse c programmers of being too obsessed with low level details, or haskell programmers with being blinded by their desire for functional purity; perl mongers for brevity, etc. But you would, IMHO, by getting the causality backwards when you do so.
When I want to write a program that is best expressed in a certain style, I try to choose a language that supports that style. Sometimes you want a tool that lets you do unusual things, and for such a task having a language such as ruby is as valuable as having mathematica for math or javascript for browser manipulation in your toolkit. If I want to play with typography I hop into postscript because that's what it's best at.
It's like saying "Have you ever noticed that people who use power drills are always poking holes in things?" It's true, but it kind of misses the point.
class Tree
def initialize*d;#d,=d;end
def to_s;#l||#r?"<#{#d},<#{#l}>,<#{#r}>>":#d;end
def total;(#d.is_a?(Numeric)?#d:0)+(#l?#l.total: 0)+(#r?#r.total: 0);end
def insert d
alias g instance_variable_get
p=lambda{|s,o|d.to_s.send(o,#d.to_s)&&
(g(s).nil??instance_variable_set(s,Tree.new(d)):g(s).insert(d))}
#d?p[:#l,:<]||p[:#r,:>]:#d=d
end
end
The double-bang: !!something
I'm not gonna write what it does. Forget that you ever saw this syntax.
Any use of metaprogramming without having thought damn hard about whether there's a better way to acheive this using the normal, non-'meta' idioms of the language, I tend to find annoying.
An obsession with "DRY" (don't repeat yourself) where some fiendish piece of metaprogramming spaghetti is invoked to avoid repeating yourself, say, twice in a simple and actually-more-straightforward-and-readable-than-the-alternative fashion.
Any use of 'eval' in particular. As metaprogramming goes, this one should be your absolute last resort after trying everything else. eg a lot of rubyists appear not to have heard of Class#define_method.
The output phase of yaml.rb; that's why I co-authored zaml.rb. The standard yaml version does all sorts of metaprogramming (it was originally written by why-the-lucky-stiff, who I generally admire) but by replacing it with a straight forward hierarchical version that directly maps to the class tree we were able to eliminate several O(n^3) cases, resulting in a factor of ten speedup for cases of interest, fix several bugs, and do so in a fraction of the code.
Plus, even people who aren't ruby gurus can see what it does.
Many of the examples in this article would seem to qualify:
21 Ruby Tricks You Should Be Using In Your Own Code.
The title of the article was a bit of a giveaway, given that it reads "Should" instead of "Should Not". Code "should" be transparent. Code "should not" be tricky.
I'm not sure if this qualifies as "too clever," but I have seen code that made me wonder if the author was either a genius or an idiot. One developer seemed to have a rule that no method should have more than two lines of code. That pushed the call stack very deep and made debugging rather difficult. The upside is that his overall design was very abstract and even elegant from a distance.
Cucumber (or RSpec Stories)
Quoted from the above RSpec Stories link:
Based around plain text descriptions
of application behaviour, it lets you
write integration tests with good
reuse and good diagnostic reporting.
For example, here's a story I wrote to
check the login process.
Story: login as an existing user
As an unauthenticated user
I want to log in to Expectnation
So I can see my account details
Scenario: login details are correct
Given an event provider
And my test#example.org account
When I log in with email test#example.org and password foofoo
Then I will be logged in
And I will be shown the account page
The words such as "Given", "When" and
"Then" are cues to the story runner to
execute some code. Behind the story
sits a collection of steps. Here's a
couple of steps from this test:
Given "my $email account" do |email|
#user = find_or_create_user_by_email({:email => email,
:password => 'foofoo',
:password_confirmation => 'foofoo'})
end
When "I log in with email $email and password $password" do |email, password|
post '/user/account/authenticate',
:user => {:email => email, :password => password}
end
Notice how a clever bit of string
matching allows you to pass parameters
from the story prose.
With a small bit of bolting together, the prose stories are then run as code and the tests executed.
It depends. (I love "it depends" questions)
It depends on the knowledge of the writer and reader. I used to think the use of Symbol#to_proc in Rails was unnecessarily arcane, for example, preferring
a.map { |e| e.downcase }
to
a.map(&:downcase)
Now I'm happy when I read it, although I still don't think to write it.
There are areas of libraries (Rails and others) where I have felt excessive and self-indulgent metaprogramming may have occurred but again the division between "too clever" and "really very clever indeed" is often paper-thin. DSLs are a good area: the ways in which "macros" are made available within classes (think of all that declarative goodness in things like ActiveRecord::Base or ActionController::Base) is very hard for a relative novice to understand and would probably seem like over-cleverness. It did to me. Now I find myself referencing the same code for guidance as I implement similar capabilities.
method_missing can be abused and it's one of those things that may cause you to pull your hair out when you have to fix a bug 3 months after you've written code.
Take a look at the source of Markaby. Insanity.
You shouldn't have to go from method to method to method to try to figure out what in the hell something is doing, for the sole purpose of not repeating a few lines of code. Being too focused on the LOC count and ultra-skinny methods might feel cool at the time but is time-consuming for someone else trying to debug or follow the code (and that someone may be you months later).
compare:
if MODELS.keys.inject(true) {|b, klass| b and klass.constantize.columns.map(&:name).include? association.options [:foreign_key]} then
# ...
end
1 line (if), 132 chars, 132 avg len, 22.9 flog
vs
fk = association.options[:foreign_key]
columns = MODELS.keys.map { |key| key.constantize.columns.map { |c| c.name } }
if columns.all? {|column| column.include? fk} then
# ...
end
4 lines, 172 chars, 43 avg chars, 15.9 flog
much faster too.
Original author actually argued maintainability for the first version.
Recently uncovered this monster:
def id
unless defined?(#id)
#id = if id = local_body.to_s[/(?:#\s*|#[[:punct:]]?)#{URL_REGEX}/,1]
id.to_i
end
end
#id
end
Not that I disagree with caching a calculation, it could just be far more clear.