1 Reply Latest reply on Sep 17, 2014 5:33 AM by Kutir Mobility

    Is an Extension the right place for our arbitrary Ruby classes/modules?

    Jon Tara

      We've often had design discussions about where to put some arbitrary Ruby class or module in our code. That is, you've written some module or class to do some specific thing, and it's not a model or controller. It's just a lump of Ruby code that you've pulled-together in one place presumably to accomplish some specific thing.


      Where to put it in your Rhodes project? It's something we've debated on our team.


      It can be awfully convenient and tempting to just make it a Rhom model. While perhaps the height of developer laziness, it's convenient, because you do not have to bother to 'require' the file(s) wherever you use them. But if it's not really a model, you still wind-up with an (empty) Rhom model anyway. We've abused this one pretty well - for example, we have a model called Const. Guess what that's about?


      We've also written a lot of "helpers"  that are not helpers. In the Ruby On Rails paradigm, at least, a "helper" is some method that gets automatically mixed-in to all of your controllers. They're meant for very general things, and Rails (as well as Rhodes) gives you a few handy starters - for example, the h() helper that escapes HTML content.


      So, in our dark history, we have a bunch of code in our "helpers" directory (where we know Rhodes won't turn it into a model...) that has no business being there.


      I had thought you could just drop it into some lower-case directory, and Rhodes would keep it's hands off, but - it turns out, not quite... There's actually not an assumption that Rhodes model directories start with an upper-case letter!

      So, if you do this (as we do) make sure you avoid having a file inside such a directory with the same name as the directory, or it will be seen by Rhodes as a model (even if not following the first-letter-upper-case convention). That is, if you create a directory called (all lower case) "foo", to contain your Foo class, make sure you do NOT have a file called "foo.rb" - because Rhodes will think it implements the Foo model! Likewise, if you should happen to have a foo_controller.rb or controller.rb in that directory, Rhodes will take it to be a controller (even if you do NOT have a model!)


      I'm thinking that the right place for your Ruby classes/modules is ... in an extension.


      Now, we have one native extension, which does some special things to make the iOS keyboard and iScroll play nice together. But, for some reason, I'd never thought to create pure Ruby extensions for common, non-model non-controller code. It seems to me, though, that's exactly the right place for them.


      I'd started to move some files out of our "helpers" directory, and extensions might not be appropriate for all of this. For example, we now have a model_mixins directory for - modules that we mix-in to models. And library_extensions, for our local extensions to Ruby core and Rhodes modules and classes. (For example, we extend WebView.)


      What is a (pure ruby) extension anyway? It's really nothing more than a directory of Ruby files, possibly with subdirectories. (Organize it as you wish.) The directory gets added to the Ruby search path and so you don't need to "require" anything (like models). You will have to remember to load the extension in build.yml, though. Just include/extend where used or access class methods directly.


      I think that extensions tend to be seen by Rhodes developers as something special and scary, to be avoided unless absolutely necessary. Perhaps, though, they are really where much of your code belongs? Instead, perhaps we should just think of extensions as "where your classes and modules go".


      I think the reason that extensions are viewed as scary is because they are presented as a solution to two fairly scary scenarios:


      - You need some native code. You will be writing scary stuff like Objective-C, Java, C++, or horror of horrors, C.


      - You want to port some Ruby library (usually packaged in a Gem) to Rhodes, hopefully just ripping out the .lib from a pure-ruby Gem. This is pretty scary, as many Gems aren't pure Ruby, and those that are often have prerequisite Gems that probably have prerequisites themselves. It can be a big production.

      So, the two things that pop into your head when you think about extensions are two things that you'd prefer not to think about.

      But what is an extension, really? It's just some code gathered into a directory, and you pre-load one file from that directory by referencing it from build.yml. That's it. Not really so scary.


      Note that extensions can be in the Rhodes framework (inside the Gem) or in your project. Of course, I am talking about "in your project" here, and wouldn't recommend adding extensions inside the Gem (though, historically, it's something that was once commonly recommended and done.)


      Where do you put your non-model classes/modules?