723 karma · joined August 3, 2008
https://practicingruby.com/articles/parsing-json-the-hard-wa...
The Ruby-based simulator discussed in this article used Rich Hickey's Clojure ant simulator as a starting point: https://gist.github.com/spacemanaki/1093917
Hickey's simulator was perhaps a bit closer to what you are looking for. It only emits one type of pheremone, which it releases on a continuous basis.
In my simulation, I introduced two types of pheremones: one emitted when food was found, and another emitted when the home was found. In retrospect, I possibly could have continuously emitted the "food" pheremone when traveling outbound, and the "home" pheremone when traveling inbound. I can't remember if I tried that and ran into trouble, or just didn't think of the idea at the time I was building this.
I vaguely remember choosing to implement things this way because it eliminated the noise generated by ants wandering in circles endlessly, but I honestly can't remember why I decided to "improve upon" Hickey's simulator.
It's worth pointing out that though the behavior of the world is very artificial (the whole trail gets marked at once after a complete path is run), the behavior of the ants themselves still only relies on their immediate location. And because these ants don't know where "home" is, they're even dumber than real ants that actually do have some sense of direction.
Anyway, refinements on this simulator or links to other simulations that illustrate these ideas are absolutely welcome! I'd definitely update the article if we found a way to improve upon what I've done.
We are working on a long term solution to that problem by finally focusing on building an extension and components layer for Prawn, which would hopefully allow all sorts of other gems to fill in these gaps. But it's a ways off into the future.
If going to Asciidoc is an option, Asciidoctor is now Prawn based for PDF output, and might make sense for simple reports:
Thanks for the feedback, I've emailed Mathias to let him know about your suggestions.
Bug reports, suggestions for improvements, and pull requests related to the cookbook can also be filed directly here: https://github.com/elm-city-craftworks/practicing-ruby-cookb...
Since we've been seeing a lot of traffic from this article, I'd be happy to also answer questions here that HN folks might have about how Practicing Ruby works!
Gary makes this claim:
> You finally get to see what's really going on. David's tests run in a few minutes, and he's fine with that.
> I'm not fine with that. A lot of other people are not fine with that.
But what DHH actually said is this:
> You might think, well, that's pretty fast for a whole suite, but I still wouldn't want to wait 80 seconds every time I make a single change to my model, and want to test that. Of course not! Why on earth would you run your entire test harness for every single line change in a particular model? If you have so little confidence in the locality of your changes, the tests are indeed telling you that the system has overly high coupling.
and this:
> These days I can run the entire test suite for our Person model — 52 cases, 111 assertions — in just under 4 seconds from start to finish. Plenty fast enough for a great feedback cycle!
Using a workflow like Gary's, there's an argument to be made that 4 seconds is not acceptable, and this is why we want single files that can run in a few milliseconds.
However, that's not the only possible way of running tests, and the difference between 4 seconds and 300ms for the feedback you're actually interested is massively different than 300ms vs "a few minutes".
For a post that calls DHH out on a strawman, this is in itself a great example of one.
If you have any questions, I'd be happy to answer them!
If you liked this article, you may also enjoy "A gentle introduction to actor-based concurrency"(*), which shows how to solve the dining philosopher's problem using Ruby threading primitives, celluloid, and a made-from-scratch actor model similar to what is shown in this article:
https://practicingruby.com/articles/shared/plgjjonrkggl
Disclaimer: I am the editor for practicingruby.com, and this is one of our contributed articles (from Alberto Fernandez-Capel).
The overall way that Ruby is developed causes these issues to happen, because major language experimentation happens very close to feature freeze dates. Because MRI is the defacto-standard (and the ISO standard defines a Ruby which simply does not exist in reality), contention happens because of the lack of coordination between the core Ruby team and the alternative implementers.
So for example, something like refinements are controversial because they are very challenging to implement and create all sorts of additional complexity. Under the current way of doing things, alternative implementers would be forced to either implement this feature or to not be able to fully claim they are "compatible" with whatever Ruby version they're released in.
Matz is generally a good BDFL, and the alternative Ruby implementers are generally very reasonable as well. But the tight time cycles, informal arrangements, and the communication barriers between a Japanese-speaking and Japanese-cultured core team and a more globalized language community combined lead to a lot of heated debates and frequent turbulence.
But all that having been said, compromises are almost always made sooner or later and the community moves forward together. They just often come at a high cost, and I wish that cost were lower. After all, the list of things we agree on is miles longer than that which we disagree about.
1) Yes, exactly my first thought as well! I've personally been gravitating to a more functional-programming inspired form of OO, and so at first these ideas bothered me. But then I thought about it a bit, and it seemed like these ideas actually push things in the direction of Alan Kay's vision of objects: fairly autonomous entities that interact solely through message passing.
In such a system, the interesting stuff gets pushed up into the messages passing between objects rather than the state and functionality within the objects. This makes it conceptually quite different than functional programming, and probably has very different pros and cons.
2) Prohibiting return values does make a big difference to the way we need to think about error handling. I think raising exceptions might be acceptable for validating inputs, but for other kinds of failures, you would need to use a callback mechanism to allow the client to handle problems. This could be an argument you pass in, as you mentioned, or there could be a mechanism by which either the caller or some other object could subscribe to failure notifications. In any case, the object that caused the failure would be responsible for how to notify its caller, if at all.
I am not sure that the argument for doing things this way is at all related to trying to make things harder or for encouraging you to write error handling at the same time you write a function (although those may be side effects). Instead, I think that the point is to centralize failure handling so that the responsible object takes care of things rather than expecting every caller to know all the possible ways things can go wrong. For the sake of brevity, I cut an example from Smyth's correspondence that perhaps I should have left intact. Hopefully it will help shed some light on this issue for you:
>4. Since there are no return values, the objects need to be
> "responsible" objects: they need to handle both nominal, and
> forseeable off-nominal cases. This has the wonderful affect of
> localizing failure handling within the object which has the
> best visibilitiy, and understanding, of whatever went wrong.
> It also dramatically reduces the complexity of protocols, and
> clients.
>
> For example, with POSIX file system calls, one needs hundreds
> of lines of code to fully handle all possible failures of the
> open() call. This code needs to be at every open() call in all
> clients, because the POSIX file system is not responsible.
>
> A responsible object would deal with the forseeable off-nominal
> cases. Then all clients benefit.
>
> Clearly, something outside of the responsible object may need to
> act if the responsible object cannot resolve a problem with local
> action. OK - then a wider scope object needs to be involved: the
> responsible object sends the problem message "up" to some object
> with broader visibility. True, this might be, in a trivial system,
> the client -- but the problem is reported as a different message,
> not a return value from the original message (don't think
> continuations, because we are talking distributed here).
SOURCE: http://www.ccs.neu.edu/research/demeter/demeter-method/LawOf...3) I stared at this "tight synchronization" statement for a long time too, and it wasn't clear to me until I realized that Smyth's primary interest was in developing guidelines that facilitate robust programming in distributed real time environments. The point he was making here, I think is roughly this: If you are not expecting return values from your functions, you can treat them as if they were all concurrent calls which immediately run in the background. You will never need to wait for a response, because you won't be calling functions on return values if you follow his variant of the LoD. Instead, results will get pushed to you via callback mechanisms only, which means that an arbitrary amount of time can pass between the time you call a function and the time that you know it has finished, and you won't need to worry about your functions blocking execution. The Ruby example I show in this article does demonstrate these ideas, through the use of threading. In a language with concurrent objects, you would get this effect "for free".
If you enjoyed this article, you might also enjoy another issue of Practicing Ruby that is on a related topic. Please check out "Responsibility-centric vs. Data-centric design", by Greg Moeck: http://practicingruby.com/articles/shared/lrwkumltjnxr
Hope that helps! I'll try to keep an eye on the conversation here, but may not have time to continue discussing things until next week sometime. Still, thanks for sharing your thoughts.
http://www.amazon.com/Penguin-Leviathan-Cooperation-Triumphs...
I'm not sure whether this happens at a regional level or across the entire country, but right now it's loading fine in Wuhan :)
It's weird how two regions connected by a subway system can be so different from one another, and yet still be the same country. My wife is a Chinese citizen but needs a visa to go to Hong Kong... as an American I don't but I need a visa to go to mainland PRC. Fun!
You don't need to be doing anything questionable to feel the bite of the GFW, webpages with Facebook like buttons are enough to cause a 30 second delay while the connection times out in the background before the site loads.
The censorship occurs at the TCP level, which is why pretty much only a VPN will help.
Right now our public facing website has very little useful information because we've grown by word of mouth and one-on-one interactions up until this point, and still manage to fill our courses up without a problem. However, in the long term we do need to do a better job of making it easier for folks to know what we're all about without having to be a friend of a friend of mine.
It's true that Mendicant University doesn't do much right now to serve the beginner to advanced beginner crowd. We had hoped that some combination of Hackety Hack and P2PU would have done that, but it just hasn't happened. Our resources are limited and so the strategy we are taking is to teach students who have some degree of Ruby experience how to get stronger, with the hope that they will turn around and help out others. Many have done so already, but in small scale efforts.
We do have a beginner's course in the works, but it may be another six months to a year before we're ready to try it out. If you are seriously thinking of starting a school for Ruby programmers which is completely free but aimed more towards beginners, please do get in touch with us. We'd love it if someone else could focus on that, because it's a real community need.
What you can definitely do (as Jordan mentioned) is get some help from our mentoring program. You'll be able to study at your own pace that way, but get some guidance as needed along the way: https://github.com/rmu/mentoring/wiki/Instructions-for-stude...
I did write one article and also did a short video on this stuff, but could think about expanding that if there is sufficient interest.
http://www.youtube.com/watch?v=BLnOD1qC-Vo http://practicingruby.com/articles/shared/oelhlibhtlkx
My work so far has been in Ruby but I'd probably want to at least look into how to do this sort of stuff in C or some other low level language, because things like alpha channel splitting in PNG is painfully slow :-/
I think that the versioning policy did work the way you describe it at one point, but it's no longer the case.
The point here is simply that you should pass the object you directly want to work with, not a class that can be used to generate that object. So if the business of your method is to actually operate on a class object, that's fine. But if you're calling new() on that class, probably not as fine.