3 ms·
I don't know Ruby at all, and maybe some familiarity with the language would help, but the biggest example code makes absolutely zero sense to me: RSpec.de
by shaftway 3y ago
I don't know Ruby at all, and maybe some familiarity with the language would help, but the biggest example code makes absolutely zero sense to me:
RSpec.describe Ticket do
context 'when the ticket is closed' do
it 'emails the requestor with a confirmation' do
...
end
end
end
I have no idea what's going on here.
I get that there are some blocks of code, though it was the indentation that told me that; "do" and "end" feel super verbose and bleed into the important parts of the code for me.
Why is Ticket capitalized? Is this a variable? An object that we're about to work on that's coming into scope?
`context `when the ticket is closed'` feels like it's setting me up. Is this an if block? Or is it some fancy way to set a listener on a property? Is this setting up a callback that'll persist across runs of the program? Or is this just a method named with spaces that could do anything?
`it 'emails the requestor with a confirmation'` has got to just be a method name. But what is "it"? What was "context" in the previous one? And why does "emails the requestor with a confirmation" need to be a block? What happens in there? Is this just setting up some kind of call stack like thing that provides context all the way down?
None of this is intuitive. And the impression that I get is that the author is calling methods with spaces in their names and unclear block semantics "expressiveness".
- binary132 3y agoIt’s a unit testing DSL for setting up a tree of preconditions / setup.
- jabbawookiees 3y agoTicket is a class do ... end is how you create no-argument functions similar to () => { ... } in JavaScript. There's some technical nuance but that's the spirit of it. In Ruby you can call methods without needing to place parentheses. So this roughly translates to the JavaScript code: RSpec.describe(Ticket, () => { context('when...', () => { ... }); }); This specific code describes a test that uses the RSpec testing framework. In RSpec, "context" and "it" are just functions that you call to describe chunks of tests and individual tests respectively. Some Rubyists would say that the combination of these syntax rules (do-end and optional parentheses for function calls) allow you to make "domain specific languages" (DSLs as they're known in the community) without needing to write your own parser. I think it's pretty plain to see the impact in expressiveness if you look at the equivalent Python unittest suite. The Python equivalent would have classes that inherit unittest.TestCase and methods named like test_when_ticket_is_closed. In Python land, classes and method declarations are repurposed because the syntax is what it is. In Ruby, you can practically make your own faux keywords by abusing do-end to accept nested blocks.
- rdoherty 3y agoYeah tbh after working with Ruby for nearly 2 decades now and with a handful of other languages I think Ruby could use some parentheses and other common symbols. It really is too easy to create what are DSLs which requires learning another language and layer of abstraction.
- drdaeman 3y agoThe syntax never bothers me (I wrote a lot of Perl code in my youth, after all), but the semantics sometimes does. I can mentally parse this (Ticket is a class name, context and it are methods that accept blocks, etc etc), but I have real hard time finding where this stuff is actually defined to see how it works underneath. And I always peek under the hood for the implementation nuances - documentation is always incomplete, so frameworks' and libraries' source code is my go-to documentation. In other languages, imports are explicit and are local to file (and people outside of ML and quick-and-dirty one-off scripting tend to recommend breaking one's fingers for a heresy of `from foo import *` - with some obvious exceptions, of course), so I always can see where exactly stuff comes from. In Ruby world there's this weird love for autoloaders, or some sort helper.rb with tons of require/include directives and so on, so very rarely I see a Ruby code that links stuff explicitly. Paired with extreme commonality of metaprogramming, reopening classes to extend them, all paired with the dynamic nature of the language, this kind of irks me as ideologically "wrong" (as in "not to my liking"). Surely, modern IDEs sort of figure out most of the stuff, but I was trying out Ruby quite a long time ago, before language servers and stuff became mainstream and widespread, and still can't shake off this impression.
- filleduchaos 3y ago> I have no idea what's going on here. > ... > None of this is intuitive. Why would anyone expect that a highly-context-dependent code snippet (in this case, a test suite written in the testing framework's DSL in a language that they both don't know and is different from the languages they usually write) would be "intuitive"? Frankly I feel like many programming language discussions are tainted by the participants tying their own intelligence to whether or not they can understand something at first glance (and if they can't, it must "obviously" be the thing that is wrong). This makes about as much sense to me as concluding that my utter confusion when glancing at a page of Portuguese poetry is somehow a problem with the language itself.
- shaftway 3y agoOh yeah, that's easy. I don't expect to be able to follow "highly-context-dependent" code snippets. The codebase I work on has a bunch of Ruby scripts with "highly-context-dependent" bits of code in them that I have to occasionally dive into to find out why they're failing. Elsewhere in this thread people are complaining about how few Ruby jobs there are. I'm eliminating one of those jobs. I replace each script with Python, or Java / Kotlin. I don't have the time to learn about all of these contexts. And I can't afford to hire people who want to specialize in Ruby. And typical engineers can't intuit about them, so nobody can properly support them. But those engineers can typically intuit between Java and Python just fine. I understand that there is Portuguese poetry and that I may not understand it. But I don't mix it into a book of English poetry.
- djur 3y agoYou're replacing Ruby scripts at work but you couldn't understand the syntax of the Ruby excerpt above?
- oezi 3y agoI think he just re-writes the scripts from scratch thinking they are more easily understood afterwards. This is usually true but only for the developer who did the re-writing.
- phaedryx 3y agoRSpec is a domain-specific language for testing written in Ruby. It isn't a great example of vanilla Ruby, in my opinion.
- TomK32 3y agoYet RSpec is one the best and easiest software to learn the idea of domain-specific languages.
- felixarba 3y agoI think you might be reading into it a bit too much. The author is saying that this code > reads exactly like how a person might talk about what they want to test A person WOULDN'T talk about testing a Ticket like what you're describing with implementation details "Ticket is a class, which will have a method of _this_ and I will call that method, which will then do _that_, and I will take the return of that method and call put it in a variable, that will be a constant..." A person WOULD talk about testing a Ticket high level like this "Let's describe a Ticket. When the ticket is closed, it emails the requestor with a confirmation." Now listen, obviously not being familiar with the syntax makes reading code harder, but a programming language isn't designed so that people can just look at the code and learn the syntax from looking at the code. That wouldn't make sense. With that said, I struggle to see some of your points listed as non-intuitive. All of your comments are related to not understanding the implementation details of this code. And that's just not what's being talked about here. I often see complaints about this when people are uncomfortable accepting _syntax_ that clearly tells them _what_ will happen, but if they don't understand HOW that happens, they don't like it. Here's another Rails example, for validating a model ``` class Person < ApplicationRecord validates :name, presence: true, uniqueness: true end ``` Can you seriously say that you don't understand that the name of the Person will be validated if it is present, and if it is unique? I doubt that very much. Can you say that you have no idea how it's implemented? Yes. You don't know how something might be implemented in a language you don't know. But, does that really matter when talking about expresiveness?
- liveoneggs 3y agoI think it does a very good job of expressing its intent? > 'emails the requestor with a confirmation' .. 'when the ticket is closed' The compiler can figure out the other bits. do .. end is { .. }