April 23rd, 2008 — General
So this week I took a small break away from Mack to build another library, Genosaurus. I found that in Mack I had basically written a generator system, so I extracted it out into a stand alone library that anybody can use, and I called it Genosaurus. Genosaurus is, in my opinion, an incredibly easy to use generator framework. Let’s be honest, we’ve all basically built a generator system at one point or another, so I’ve just wrapped it up nicely. The next release of Mack, due out the end of this week, will have all it’s generators converted to use Genosaurus. Let’s take a look at a section of the README for Genosaurus:
Implied Manifests
The easiest way to use Genosaurus is to let it do the work for you. Let‘s looked at what‘s called an ‘implied’ manifest:
dir:
simple_generator.rb
templates:
hello_world.txt.template
That‘s our folder structure. Now let‘s look at simple_generator.rb:
require 'rubygems'
require 'genosaurus'
class SimpleGenerator < Genosaurus
end
Now if we run that generator:
$irb: SimpleGenerator.run
We should get a file called hello_world.txt generated in the current directory. Yes, it truly is that simple! With implied manifests our directory structure under ‘templates’ tells the whole story, and Genosaurus is smart enough to figure it out. All the file names, and the same goes for folders, need to end in .template, and Genosaurus will do the rest. All the files will go through ERB before they generated, so you can put all your lovely little dynamic goodies in there. File, and folder, names also get run through ERB so you can even make the file name dynamic too! Let‘s look at a more complex example:
dir:
complex_generator.rb
templates:
app:
views:
<%=param(:name).plural%>.template:
hello_world.html.erb
models:
<%=param(:name)%>.rb.template
Let‘s run our complex_generator.rb file:
require 'rubygems'
require 'genosaurus'
class ComplexGenerator < Genosaurus
require_param: name
end
Now if we run that generator:
$irb: ComplexGenerator.run("name" => "user")
Now you should end up with the following:
app:
views:
users:
hello_world.html.erb
models:
user.rb.template
In the ComplexGenerator we told Genosaurus that we are requiring that the parameter, name, be passed into it. We are then using that parameter to generate the names of some files and folders. Pretty cool, eh? See how simple that is.
Explicit Manifests
Explicit manifests are used when there is a manifest.yml supplied at the same level as the generator. If there is a manifest.yml file then implied manifests are not used. This means you have to define the entire generation process. This is great if you have a pretty complicated generator, as the manifest.yml is also sent through ERB before being loaded. Let‘s look at the manifest.yml file for our simple_generator example:
template_1:
type: file
template_path: <%= File.join(templates_directory_path, "templates", "hello_world.txt.template")
output_path: hello_world.txt
Pretty simple. We give the template a name, template_1, it really doesn‘t matter what it is, but Hash objects need keys. The ‘type’ parameter is either file or directory. The template_path is the path to the template. Finally, the output_path is the where you want the file to be generated. Let‘s look at our more complex example. We can change the directory structure a bit, since we really don‘t need ERB in the file names now:
dir:
complex_generator.rb
templates:
hello_world.html.erb.template
model.rb.template
Our manifest.yml file would look like this:
hello_world_template:
type: file
template_path: <%= File.join(templates_directory_path, "templates", "hello_world.html.erb")
output_path: <%= File.join("app", "views", param(:name).plural, "hello_world.html.erb") %>
model_template:
type: file
template_path: <%= File.join(templates_directory_path, "templates", "model.html.erb")
output_path: <%= File.join("app", "models", "#{param(:name)}.rb") %>
This will generate the exact same thing as our implied manifest.
April 9th, 2008 — General
I’ve been asked by people why I’m not using spec tests to test Mack. I’m currently using just plain old regular unit tests for my tests. It’s a good question, but not really a valid one, I think. Should it matter what type of tests I’m using as long as I’m testing? Tests are tests. The framework you use to do your tests is moot as long as the tests you write are good, solid tests.
I jumped on the spec test bandwagon about a year or so ago. I forced my whole team to start writing in nothing but spec tests. The team, is still not impressed. If I were to tell them we weren’t using spec tests anymore, they would be EXTREMELY happy with that.Spec tests are certainly prettier than ‘regular’ tests. I’ll give you that. They are more ‘human readable’. With that said I find assert_equal to be fairly easy to read.
So why do I use regular tests, and not spec tests? A couple of reasons. First, they’re there and built right in to Ruby, ready to go, no new gems or syntax to learn. They’re fast. They are faster than spec tests. I see it everyday at work. I can also, and this one is HUGE, run just a single test or a regex’d series of tests. I really love that last bit. I have yet to find a way to do that, easily, with spec tests.
Again, how people write tests doesn’t really matter so much to me, it’s just that they write them. Testing is too easy in Ruby, there’s just no reason for not writing them.
March 26th, 2008 — News, Releases, Updates
It’s finally here! The release you’ve all been waiting for, 0.4.0!! What’s new in this one? Well, the big one, DISTRIBUTED ROUTING!!! Now you can share your routes between all of your Mack applications.
I’m very excited about this release. This is one of the first features that starts to set Mack apart from other Ruby frameworks such as Rails and Merb. Mack is trying to set itself as the framework for doing multiple, distributed, portal applications. This release gets us headed in that direction.
There will be a tutorial post and app in the next few days. In the meantime I highly encourage you to download this release and check it out.
Changelog:
- Added Distributed Routes!
- gem: mack_ruby_core_extensions 0.1.3
- removed gem: ruby_extensions
$ sudo gem install mack
March 26th, 2008 — News, Releases
Mack has been using a combination of the ruby_extensions gem as well some local extensions to the Ruby core in order to make Mack as wonderful as it is. In an effort to make life a little simpler, as well as to help share the wealth, the ruby_extensions gem and the Mack extensions have been combined into a single new gem called mack_ruby_core_extensions.
One of the main Mack pieces that has been broken out into this new gem is the inflection system. Now you can have inflections as part of any Ruby application just by requiring the gem. As far as I can tell this is the first stand alone inflection system for Ruby. I know because I couldn’t find one for Mack, that’s why I had to write one.
This gem will continually be updated, outside of the core Mack code. The forthcoming release of Mack, 0.4.0, will be converted to use the new gem.
Those who wish to contribute to the gem can find it on GitHub at: http://github.com/markbates/mack_ruby_core_extensions
The API for mack_ruby_core_extensions can be found at:
http://mrce-api.mackframework.com/
$ sudo gem install mack_ruby_core_extensions
March 19th, 2008 — News, Releases, Updates
I’ve been holding back this release so I could get distributed routing into it, but it appears that there’s still a little more work that needs to be done before it’s ready to go. I’m hoping to get it out by the beginning of next week, but don’t quote me on that.
Instead of focusing on what didn’t make it in, let’s talk about what did make it in! There’s some cool stuff in this release.
Format Driven Content
Mack now allows you to drive different content based on the format requested. For example:
/posts - will render app/views/posts/index.html.erb
/posts.html - will also render app/views/posts/index.html.erb
/posts.xml - will render app/views/posts/index.xml.erb - A special note *.xml.erb files, despite their name, do NOT get run through ERB, instead they use the XML Builder library
/posts.js - will render app/views/posts/index.js.erb
etc…
Alternatively, in your action you can now define ‘want’ blocks, to run specific code based on the format. Example:
class PostsController
def index
# find all the posts in the system
@posts = Post.find(:all)
wants(:html) do
# this will only be run if html is requested.
# we need a username for a 'welcome message in the view'
@username = @user.username
end
wants(:xml) do
# this will only be run if html is requested.
# find the last published date
@last_pub_date = Rss.find_last_by_date_by_object(:posts)
end
end
end
XML Builder Support
I’m not going to go into this, there is another nice post coming shortly that will explain how to use this library to add RSS to our blog demo. Here’s the post.
Built-in Encryption
In every app I’ve ever built I found the need to use encryption. Whether it’s for encrypting something into a cookie, a password in the database, or a file on disk, we all need encryption, so I’ve baked the crypt gem into Mack.
At the very simple level you can easily do this in your code:
@my_encrypted_value = _encrypt("hello world")
and you’ll be returned a nice pieced of garbled data using the Crypt/Rijndael library. Decrypting is just as easy:
_decrypt(@my_encrypted_value) # => "hello world"
See, I told you it couldn’t be easier. It gets even better you can even define your own ‘worker’ to implement other encryption schemes. It’s as simple as this:
class Mack::Utils::Crypt::HorribleWorker
def encrypt(value)
value.reverse
end
def decrypt(value)
value.reverse
end
end
_encrypt("hello", :horrible) # => "olleh"
_decrypt("decrypt", :horrible) # => "hello"
See how easy that was? You can also do:
@my_encrypted_value = "Hello".encrypt
@my_encrypted_value.decrypt #=> "Hello"
Either way it’s now easy to handle encryption in your funky cool Mack app.
Changelog:
- Ticket: #8 Xml Builder Support
- Ticket: #7 Ability to drive certain content based on ‘format’
- Ticket: #9 Added a global encryption system to make encrypting/decrypting of strings easy to use
- gem: builder 2.1.2
- gem: crypt 1.1.4