The Project Layout of a Pakyow App
If you are familiar with the structure of a Rails application, then you might find the Pakyow app layout a bit more relaxed. There are a few files that are expected to be in certain places, but other than that, you have a practically free range to roam. For some people this will feel liberating, for others it will represent the path to chaos and confusion. Sounds fun right?
Ok so lets walk right into a new Pakyow application:
$> gem install pakyow
$> pakyow -v
Pakyow 0.11.3
$> pakyow new layout
$> cd layout
$> ls -A
.bundle .gitignore Gemfile.lock app public
.env .rspec README.md bin spec
.env.example Gemfile Rakefile config.ru
Basics for Beginners* (the root directory)
Let’s knock out the basics first.
- .bundle is a directory used by bundler to hold config;
- .gitignore is a file used by git that specifies files not to be tracked in git;
- .env is used by the dotenv library that pakyow uses for supplying environment variables to the program, and .env.example is an example;
- .rspec is used by rspec to set up configuration;
- README.md is where you can describe your application;
- Gemfile and Gemfile.lock are used by bundler to install and manage dependencies;
- Rakefile is where you can set up or load rake tasks
- bin is a directory where all the executable binaries the app uses are found;
- public is the directory from which static assets are served;
- spec is where application tests live; and finally
- app is where application code goes.
Most of these are self-explanatory in terms of project layout. The app, spec, and public directories deserve some further explanation. Let’s start with spec and public, which are the most basic.
A Place for Tests
The spec directory is where your application tests will go. By default, testing is done with rspec (which is why .rspec is included in the project). You will find a couple of files already there in a new project.
$> tree spec
spec/
├── integration
│ └── app_spec.rb
└── spec_helper.rb1 directory, 2 files
You have a spec/spec_helper.rb that sets up the environment for testing your application and loads helpers that should make testing easier. And you have your first test at spec/integration/app_spec.rb which gives you a small demonstration of pakyow-test helpers, and which should pass when you run rspec.
$> rspecRandomized with seed 21014Pakyow::App
when navigating to the default route
succeeds
says helloFinished in 0.02071 seconds (files took 1.82 seconds to load)
2 examples, 0 failuresRandomized with seed 21014
A Place for Assets
In the public directory, you can place any static files that you want to load in your application. Pakyow currently does not have an asset pipeline (like in Rails) so you will most likely be placing most of your assets in the public directory. When you create a new app you will find a number of files already in the public directory: some images, a basic set of stylesheets, and most importantly, public/scripts/ring. Pakyow’s ring is the client side library that executes DOM manipulations in response to instructions in the View Transformation Protocol sent by the server via websockets. This is what makes realtime changes possible on the client.
The Hard Core
The core of the application of course lives in the app directory. This is where you will set up your routes, views, and all the code that is going to get the data you want to show up on the page. Here is what you get from a new application:
$> tree app
app/
├── lib
│ ├── bindings.rb
│ ├── helpers.rb
│ └── routes.rb
├── setup.rb
└── views
├── _templates
│ └── default.html
└── index.html3 directories, 6 files
Loading the Environment
The app/setup.rb file is where the app initialization process begins. This is the file that requires pakyow itself and sets up configuration for the app. Loading this file automatically loads all the files in the app/lib directory recursively. This means two things:
- Great! No need to specifically require anything in the app/lib directory; and
- Of course the exception, which is that if you depend on a file that has not been loaded yet (load order is alphabetical), then you do need to specifically require it.
Pakyow doesn’t have an automatic code loading system like the one used in Rails (it doesn’t want to have one, either). Files are automatically reloaded during development if they are changed, but you should keep in mind the limitations of code reloading (and the caveat above in #2) if you ever run into any strange issues. If in doubt (during development), restart your server and see if the problem resolves itself.
It’s All About the Views
The app/views directory may seem pretty obvious, but I just want to point out a couple of things. In app/views/_templates, you will find the layouts which you can apply views (default.html being the default layout). Just FYI, their is an open issue on the Pakyow repo for changing the name of templates to layouts, so there is a good chance that this will change in the v. 1.0 release. Another thing to note is that the path of the view is important. While creating a route you can specify the path for a view, but by default that view will be available at the path (/path/to/view). For example.com, if you have a view at app/views/users/new.html then you will be able to reach that view at http://example.com/users/new.
This really makes since for Pakyow, and it is consistent with its core concept of View First Development. If the app/views layout structure can be seen as as the routes structure, and the routes are just blocks of ruby code that set up the view.
(I will be covering setting up views and routes in another blog post, so look for that, or for now, check out the Pakyow Docs.)
Bindings, Helpers and Routes, oh my!
There are a few files in app/lib that are generated with a new project.
- bindings.rb is the place to define how scoped data will be bound to views;
- helpers.rb is the place to define methods that can be accessed through the app context (e.g. anywhere in routes, bindings, etc.); and
- routes.rb is where you define routes and code to be executed when a route is hit.
(I will also write articles on each of the above, but here are some basic examples.)
<!-- users/profile.html --><div data-scope="user-profile">
<h1>
<span data-prop="name">User's</span>
Profile
</h1>
<dt>D.O.B.</dt>
<dd data-prop="birthday">1988.08.13</dd>
</div># helpers.rbmodule Pakyow::Helpers
def current_user
@_current_user ||= User.find(session[:user_id])
end
end# routes.rbPakyow::App.routes do
get :profile, 'users/profile' do
view.scope(:"user-profile").bind(current_user)
end
end# bindings.rbPakyow::App.bindings do
scope :user_profile do
binding :birthday do
bday = bindable[:birthday]
current_year_bday = Date.new(
Date.today.year, bday.month, bday.day
)
part :class do |klass|
ramp_up_time = current_year_bday - 15
if (ramp_up_time..current_year_bday).include?(Date.today)
klass.ensure('coming-up')
end
end
part :content do
bday.strftime('%Y.%m.%d')
end
end
end
end<!--
If we had a User with data =>
{ name: 'Pakyow', birthday: Date.new(2011, 8, 20) },
and today was the 10th of August, we would get the following
html for the route: /users/profile
--><div data-scope="user-profile">
<h1>
<span data-prop="name">Pakyow</span>
Profile
</h1>
<dt>D.O.B.</dt>
<dd data-prop="birthday" class="coming-up">2011.08.20</dd>
</div>
Where to Put the Rest
Well, that’s everything that Pakyow generates for you when you create a new project, but what about business logic, models, and other Pakyow objects like mutators and mutables?
Remember what I said at the very beginning? Pakyow doesn’t really care. You could create a lib directory to put your business logic and models in and require them in your app/setup.rb file, or you could put them in the app/lib directory and let Pakyow load the code automatically. It’s up to you.
By convention mutators and mutables, two kinds of objects that participate in the realtime aspect of Pakyow apps, are placed in app/lib/mutators and app/lib/mutables. But it’s not required. Likewise, there is no need to keep all your routes or bindings in a single file. Branch out anyway you want (just keep in mind the limitations of the loader was mentioned above). The more you experiment and share your experience with our community, the better the conventions will be.
Examples
If you have written a Pakyow app, and want to share it, let me know and I will check it out and add it to the list below.
Pakyow project examples on Github:
*Harry Potter reference. If you don’t get it, that’s okay, just move along.