1. 5
    def parse(order_filename)
       eval File.read(order_filename)
    end
    

    Isn’t this like super dangerous?

    1. 2

      Thanks you for your feedback !

      Bundler use the same approach to evaluate gemspecs file. And almost the same approach for the Gemfile..

      So, as bundler is used thousands of times per day, then the practice doesn’t seems so dangerous.. hehe

      The main point here is that I use eval in a safe context: reading a file that will be edited by the developers themselves.

      It’s not an eval in a controller action.

      1. 2

        Don’t developers use gemfiles (and in this case, config files) written by unknown third parties (other developers) too, though? I don’t want to have to audit a config file for security.

        1. 7

          Downloading code from the internet and then running it is a security vulnerability. It really is a wonder that most language specific package managers don’t trouble themselves with anything as sophisticated as an integrity check, let alone a signature, let alone any kind of sandboxing by default.

          Ruby isn’t the only offender, in most languages, “bundler doesn’t work try running it with sudo, there you go” is standard operating procedure.

          There are real package managers out there that attempt to tackle these problems and more (like guix), but they’re not the norm, and I don’t think any of them are perfect.

          1. 2

            We considered this when building RubyGems, and in fact there was a competing ruby package manager at the time called RPA that tried to address these issues (https://github.com/threedaymonk/rpa-base). The problem is that for signatures to be meaningful, you have to establish a web of trust.

            Since that’s a hard problem, and we were building a package manager from scratch at the back of a hotel bar at a programming conference so it could be demoed the next day, we decided to stick with what we could solve in an evening (and in any case installing a gem from rubygems.org is at least as secure as installing a tarball from the Ruby Application Archive, which is what we were hoping to replace (http://web.archive.org/web/*/http://raa.ruby-lang.org/)).

            I still hope that one day someone will figure out a way for programmers to share code with each other with minimal friction, but also be able to trust the code that is being shared without accepting it on blind faith.

          2. 2

            Having the gemspec be arbitrary Ruby code is a problem. Less so on the client and enduser (it runs most of the code downloaded from rubygems.org anyways, it doesn’t add much) than on the systems that actually need to digest them, like the rubygems host itself! AFAIK, for that reason, rubygems dumps the data it needs locally on the machine before publish. AFAIK also, the gemspec is not loaded on installation.

            But that still means all tooling that wants to look at the gemspec (dependency update bots etc.) need to run it to get all the data out, especially because people do modify the gemspec to read external resources or similar.

            There’s tons of problems coming out of that, which is why most second-generation bundlers don’t use code (interestingly, https://conan.io/ though uses Python for that).

            The Gemfile being code is less so a problem, as it’s the code component that loads the dependencies in your app. It’s usually handwritten and frequently looked at. If I wanted to hide something, I’d hide it in a loaded dependency, as Ruby can evaluate arbitrary code during require even.

            1. -3

              💯

          3. 1

            Dangerous in which sense?

            I will agree that eval should generally be avoided, since it can accidentally clobber local variables. The code in the post does not uses eval, however; it uses instance_eval.

            If you mean dangerous in a security sense, then you are correct that you should not pass untrusted strings to eval/instance_eval/class_eval. If the string is from an untrusted source, it should be evaluated inside a sandbox. There are a number of libraries/gems that provide sandbox functionality, though I’m not sure which is the best to use these days.

            1. 2

              The code was eval when I wrote that an was later changed to instance_eval.

          1. 3

            Did the author not know about cloc?

            1. 3

              Update page for this project: https://github.com/AlDanial/cloc

              I also found this section in the intro documentation very graceful:

              https://github.com/AlDanial/cloc#other-counters-

              If cloc does not suit your needs here are other freely available counters to consider

              1. 2

                I know this tool. But the purpose of the blogpost is to describe the find library in Ruby. The script is just here to illustrate a use case of this library. Nothing else.

                Anyway, thank you for the tip. :-)

              1. 3

                The eigen- prefix is used to describe something which is “the same” before and after a transformation. e.g. the eigenvector of a matrix is a vector which still points in the same direction after multiplying by the matrix (scaled by its eigenvalue). What exactly is the transformation going on here?

                1. 6

                  eigen comes from Germanic languages such as German and Dutch where it means own, particular to, etc.

                  Mijn eigen auto -> My own car.

                  Mijn eigenwaarde/eigendunk -> My self-esteem

                  So, the prefix eigen- does not imply a transformation. Though, I agree that it is confusing in CS to use this prefix, since non-native speakers immediately associate it with eigenvalues/vectors.

                  1. 2

                    The term “singleton class” that the article briefly mentions is actually Ruby’s official term for this concept. Ruby’s standard library defines the Object#singleton_class method; you can use .singleton_class in place of .eigenclass in all the article’s examples. Perhaps this potential confusion is the reason the Ruby team chose “singleton class” over “eigenclass”.

                    1. 2

                      Thank you for your comment.

                      Eigen means “own” in German. So “eigenclass” means “owned class” (as this anonymous class is owned by its defined class).

                      1. 2

                        Etymologically speaking, the “eigen-”-prefix was used by David Hilbert to describe that the value/vector is inherent to the thing. To confuse things a little, “eigen” is a pretty versatile word in german: https://www.dict.cc/?s=eigen

                        Hilbert probably used in the sense of “possessive”, “inherent”, “in-built”. In that sense, which is not focused on the transformation, “eigenclass” is rather similar.

                        (loosely taken and translated from: http://faql.de/etymologie.html#eigen)

                      1. 1

                        I believe the ‘show’ tag is appropriate when posting your own blog.

                        Congrats on the blog and kudos to the dedication! I am personally really bad at blogging because I treat each post as an essay that has to perfectly and thoroughly convey my thoughts.

                        1. 4

                          To me show is to show projects or things you’re done more than to indicate a self-posting. This is already an information displayed by “authored by” next to the Lobsters who posted the link.

                          1. 2

                            This is correct.

                          2. 1

                            Thanks for the tip about the tag.

                            It’s effectively hard to determine when your article is “ready”.

                          1. 3

                            Due to duck typing design, Interface Segregation and Dependency Inversion principle are not relevant in Ruby.

                            Sorry, but I strongly disagree with you on this statement. I understand some ruby developers have an aversion to any type system or any formality, but being highly dependent on DT can cause you serious problems. Specially when you’re working with a large codebase, that has been around for a while and abuse on monkey patching.

                            Here are two good examples where these principles can be applied successfully in ruby and help you bring some sanity to your projects.

                            http://rubyblog.pro/2017/07/solid-interface-segregation-principle http://rubyblog.pro/2017/07/solid-dependency-inversion-principle

                            1. 1

                              Thanks for your feedback.

                              But, this is not ISP.. The example doesn’t follow the principles:

                              • Clients should not be forced to depend on methods that they do not use. OK
                              • Many client specific interfaces are better than one general purpose interface. KO

                              This example show a FeeCalculator that provides 2 methods..

                              1. 2

                                ISP definitely does apply to Ruby, or any other language, because the principle in itself is not dependent on language constructs. It’s easier to visualize in statically typed languages because it’s explicit, it’s something you need to write. When working with dynamic languages, the construct doesn’t exist explicitly, but you’re still making design decisions about how the classes interact with each other. Understanding and reasoning about how much one class know about another in a given context, is exactly what ISP is about.

                                For example, in Ruby’s standard library, we have a File and a StringIO class. They each have their own methods, but they also share a smaller common interface. That is not accidental, the library designers made a conscious decision to have similar methods so that the class can be used interchangeably in specific contexts.

                                As a user of those libraries, you also have an option. You can use methods on those classes that are specific to each one, or you can organize your code in a way where you pick a very small interface that you’re gonna depend on. If you only use methods that are available on both classes, you can pass any of those classes into your component and it will just work.

                                The main difference on dynamic languages is that you don’t have a fixed set of interfaces that are provided by the library authors. You have a number of interfaces that is equal to the combination of all methods available in that class API.

                            1. 7

                              My thought is that “duck typing” in Ruby is merely a consequence of object polymorphism. Like Smalltalk that so influenced it, Ruby allows requests (messages) to be sent to an object which might handle them or not. For example, one might have a collection of objects and request that each “fly”. Whether they can or not is determined at runtime.

                              So I contend that it doesn’t “encourage it”. Rather “duck typing” in this context is a name indicative of how object polymophism in Ruby is achieved.

                              1. 12

                                “Duck Typing” is just interfaces without the type system.

                                An interface is a set of methods implemented by an object. An object can be explicitly declared as fulfilling an interface (like in Java) or it can be implicit if the object implements all off the interface’s methods (structural typing, like in Go).

                                The problem with doing this with dynamic languages is, of course, that you won’t know if your object correctly implements all of the interface until runtime. Worse, with “Duck Typing”, there is no formal definition of the protocol that you can check, even at runtime.

                                In SmallTalk, interfaces are called “protocols” (in fact that’s the name I typically use to talk about that concept, even though I include a little bit more in the notion that just the interface, but I digress). The fact that protocols are not formalized in SmallTalk is not a design choice, see Future Work here:

                                [In Smalltalk-80] message protocols have not been formalized. The organization provides for protocols, but it is currently only a matter of style for protocols to be consistent from one class to another. This can be remedied easily by providing proper protocol objects that can be consistently shared. This will then allow formal typing of variables by protocol without losing the advantages of polymorphism.

                                Incidentally, it looks like Pharo did formalize protocols.

                                This is not to say that using Duck Typing in languages that provide no typed option for structural typing is bad, but a little more formalism and safety cannot hurt in that respect.

                                1. 6

                                  Ruby - the project and community - does encourage it, through it’s use in the stdlib and in general practice.

                                  Interestingly, this hasn’t always been the case, the push towards making Ruby a duck-typing ecosystem and adopting it as a strategy was with 1.8, shortly before Rails. See https://viewsourcecode.org/why/hacking/rubyOneEightOh.html, “Duck typing and to_str”

                                  1. 1

                                    Interesting!

                                    Also, I feel that it’s natural to use duck typing in the context of a dynamically typed & fully object-oriented language such as Ruby.

                                  1. 2

                                    You do a decent job of using the phrase “alias keyword” however I notice the heading for that section is labeled “the alias method” (it’s not a method as you correctly state otherwise).

                                    I think a phrase that is potentially missing is “lexical scope”

                                    1. 1

                                      Oh sorry for the typo hehe.

                                      Yep, I explain what’s a lexical scope without explicitly naming it.

                                      I gonna update my post. Thanks for your feedback ;-)

                                    1. 2

                                      There is a public_send method that respects method visibility - to be completely honest I’m not sure how it deals with protected status, though, since protected is not typically seen in idiomatic Ruby afaict.

                                      I do like the perspective of looking at method dispatch in terms of sending messages, though. Decent write up!

                                      1. 2

                                        public_send does not call protected methods. And, yeah, protected rarely happens in Ruby. I consider it a mild code smell as it implies the use of inheritance.

                                        1. 1

                                          And, yeah, protected rarely happens in Ruby. I consider it a mild code smell as it implies the use of inheritance.

                                          I’ve always considered private to be the wrong choice, in any language, because it signals that I think I know every way anyone might ever want to extend my class. Inheritance may not always (or even often) be the right solution, but making certain extension options impossible is just going to drive future coders crazy.

                                          1. 2

                                            I use private to lower the cost for future internal refactors, and upgrades, by providing a signal that “Hey, this method is not part of the public API, I do not condone its external use, and reserve the right to change it wildly.”

                                            It communicates that there consciously was no consideration for what might happen if external objects began to depend on said private method. Later changes by anyone (not just the original author) can and will be free to change the private method at will: refactor, upgrade, remove entirely, and there is less to hold in your head and worry about when upgrading them later.

                                            However, behavior of a private method that is observable through the a public method is fair game, and test cases should exist for those. The flip side of this is that, except in some rare cases, I favor not testing private methods. Any behavior that is possible via a private method, but which cannot be exercised or observed through use of public methods, should not be considered as supported behavior on the object. That does not preclude a new public method from exposing more of the private method’s behavior later, but at that point it is part of the public interface, and should be presented and documented as such.

                                            As for making certain extension options impossible, at least in the context of Ruby, private does not do this.

                                            class PrivateGreeter
                                              private
                                              def greeting
                                                "Hello."
                                              end
                                            end
                                            
                                            class PublicGreeter < PrivateGreeter
                                              def speak
                                                greeting
                                              end
                                            end
                                            
                                            irb> PrivateGreeter.new.greeting
                                            # => NoMethodError: private method `greeting' called for #<PrivateGreeter>
                                            irb> PublicGreeter.new.speak
                                            # => "Hello."
                                            

                                            You can even give it the same name as the parent class’ private method if you really, truly need to let external objects utilize the method as part of the subclass’ public API with the exact same name:

                                            class PublicGreeter < PrivateGreeter
                                              def greeting
                                                super
                                              end
                                            end
                                            
                                            irb> PrivateGreeter.new.greeting
                                            # => NoMethodError: private method `greeting' called for #<PrivateGreeter>
                                            irb> PublicGreeter.new.greeting
                                            # => "Hello."
                                            

                                            Since an inherited class can make use of its parent class’ private method, the question then becomes: should it? If we have a stipulation that the parent class reserves the right to refactor its private methods or change them wildly, should we rely on a parent class’ private method?

                                            I think the answer differs between application code and library code. If the parent class comes from a library, or some internal, but still cross-domain, utility code, I would not want to rely on the existence, the arity, or the behavior of a private method. If the behavior is so critical, I would rather capture the behavior permanently as part of the subclass by copying the code itself over to the subclass (or not use inheritance at all, but I would still definitely copy the code). Everything I have seen makes me agree that duplication is far cheaper than the wrong abstraction.

                                            In the case of application code, it is more acceptable to rely on a parent class’ internals. I still would fight the urge, but it can be expected that the author modifying the subclass and parent class has access and authority to work on both in order to get their job done, that the tests for both classes live in the same suite, and other niceties that make maintaining that dependency across time situation more tenable.

                                        2. 1

                                          Thanks for your great feedback ! That’s motivates me to do even more :-)

                                        1. 1

                                          Non-Ruby developer here. Is there any difference between a Ruby yield and just passing in a lambda as an argument?

                                          1. 2

                                            Yes, though there are a few aspects in play here. First, a block parameter is a special argument and in order to pass a lambda in as a block parameter you must use the & operator (this operator will attempt to coerce non-proc objects to procs, so this is why symbols are sometimes used in this way).

                                            When you have a block in ruby, the lifetime of the lexical context is tied to the call-frame that is created upon invocation. This might sound like an implementation detail but it allows the runtime to avoid allocating a proc object to hold the closed over lexical environment (aka. faster and lighter). Generally, if you know you’re receiving a block, it can be an advantage to stick with yield and the implicit parameter rather than pull out the proc as a value and use #call (or an alias of #call like #[]) on the object (this has been optimized more recently in some cases to allow lazy allocation of the object if you only forward it to another call).

                                            The other difference is around parameter behavior. Blocks and Procs don’t require the arity of the block and the yield to match. So you can take fewer or more arguments than are passed and the extra fields will either be dropped or set to nil. Lambdas however, require the arity to match, much like a method call (distinctly constructed using lambda or -> “stabby” syntax). This can be a good thing but I’ll avoid writing half an article here.

                                            One more advanced case that many are unaware of, you can capture a proc using the constructor without a block, so these end up working in a similar way:

                                            def a_is_42(a, &callable)
                                              callable.call if a == 42 && callable
                                            end
                                            
                                            def b_is_42(b)
                                              Proc.new.call if b == 42 && block_given?
                                            end
                                            

                                            Of course, it’s a contrived example on the second because we could just use yield there, but it does show that we can build the proc object lazily which can be a big win in some hot paths for Ruby code. There are some more optimization techniques but this gives a little taste of the range of differences between the proc world and the block world. If people are curious, I can write up more about this stuff.

                                            TL;DR, you can avoid a lot of allocation and call overhead by keeping things in block form.

                                            1. 1

                                              That makes sense, thanks!

                                            2. 2

                                              The only difference is that your lambda will be an instance of the class Proc which is in charge of storing and executing the piece of code associated to your lambda.

                                              It’s a bit more complicated than this, but let’s keep it simple if you’re not familiar with Ruby. ;-)

                                              I invite you to read this article to dive into the specificities of the Proc class and lambdas in Ruby.

                                              1. 1

                                                Which article?

                                                  1. 1

                                                    Thanks!

                                            1. 1

                                              Agree with you. Sidekiq is a great example of this. :-)

                                              They’re also very useful for app configuration and DSLs.

                                              1. 10

                                                Nice write up on the OpenStruct object in ruby!

                                                However, I have to do my due diligence here. For most (all?) cases, using OpenStruct is a terrible anti-pattern. Any OpenStruct object will respond to any method you call on it and if it doesn’t exist, returns nil. This causes uncertainty within the system and makes testing a nightmare.

                                                As I recommend to most people, you’re better off using a PORO (plain old ruby object)!

                                                1. 10

                                                  And anima makes it very easy to avoid OpenStruct/Struct.

                                                  1. 1

                                                    Nice! TIL!

                                                  2. 3

                                                    Using OpenStruct can also kill your performance due to effects it has on the global method cache.

                                                    1. 2

                                                      I thought so too, until a friend corrected me: That was fixed several years ago and isn’t still the case.

                                                    2. 2

                                                      Thanks for sharing your precious experience with OpenStruct :-)

                                                      Anyway, the goal of my articles is just to describe a notion as deeply as possible. I prefer to keep a neutral point-of-view because each notion that I describe can be useful in many cases.

                                                      Implementing the notion in real use cases is just a matter of sensitivity for each developer.

                                                      That’s why I’m glad that you share your opinion and your experience with the OpenStruct class here.

                                                      1. 2

                                                        I like reading about all the nooks and crannies about Ruby so your articles are very interesting to me! Thanks for sharing.

                                                        1. 1

                                                          Why do you want that neutral position? One of the things I really love in articles is seeing how people evaluate the benefits and risks of tools like OpenStruct. I get to understand when to use or not use something, learn general strategies useful for other tools. Let the documentation be non-judgemental description, I want experienced opinions. :)

                                                          1. 1

                                                            Actually my articles are made to demystify a misunderstood or opaque notion. By doing so, developers can take the decision to apply the notion or not by knowing all the aspects of it.

                                                            Also, this enhances their general culture about the language.

                                                            After, your point of view is also correct. Maybe, in a near future I’ll start to share my experience with the notions that I treat in my articles.

                                                            Thanks for the feedback. It’s really appreciated :-)

                                                      1. 3

                                                        It’s worth noting that some people consider inheriting from Exception rather than StandardError to be bad style. Because catching Exception includes things like ScriptError::SyntaxError and SignalException::Interrupt (^C), the advice seems to be to catch StandardError instead if you don’t know what exceptions to expect and thus your custom exception classes would need to inherit from StandardError to match that.

                                                        1. 3

                                                          Yep, and some common libraries (looking at you, nokogiri) don’t follow this advice and instead throw things like SyntaxError that should be limited to the Ruby parser itself.

                                                          1. 0

                                                            Actually, It’s better to create a custom error that makes sense within the execution context.

                                                            Anyway, Thank you for the precision. :-)

                                                            But the purpose of my articles are just to explain how it works, not how to use it.

                                                            I believe in the fact that developers are not robots and they’ll learn all the aspects of a notion by using it, repeatedly. Instead of telling them what’s good or not, I prefer let them figure it out by themselves.

                                                            I prefer put all of my energy on explaining the main concept and let the 5% of edge-cases on side.

                                                            But, again, thanks for your precious feedback :-)