├── .document
├── .gitignore
├── HISTORY
├── LICENSE
├── README.rdoc
├── Rakefile
├── bin
└── choco
├── choco.gemspec
├── lib
├── choco.rb
└── choco
│ ├── cli.rb
│ ├── dependency_manager.rb
│ └── generators
│ ├── app_generator.rb
│ ├── controller_generator.rb
│ ├── fixture_generator.rb
│ ├── layout_generator.rb
│ ├── model_generator.rb
│ ├── plugin_generator.rb
│ ├── scaffold_generator.rb
│ └── templates
│ ├── Jimfile
│ ├── README.rdoc
│ ├── Rakefile
│ ├── application.css
│ ├── choco
│ ├── config.ru
│ ├── controllers
│ ├── application_controller.js
│ ├── base_controller.js
│ └── rest_controller.js
│ ├── fixtures
│ ├── base.js
│ └── model
│ │ └── array.js
│ ├── help
│ ├── commands
│ └── generators
│ ├── helpers
│ └── application_helper.js
│ ├── index.html
│ ├── lib
│ ├── application.js
│ └── plugin.js
│ ├── models
│ └── base.js
│ └── views
│ ├── edit.template
│ ├── index.template
│ ├── layout.js
│ ├── main
│ └── index.template
│ ├── new.template
│ └── show.template
└── spec
├── choco_spec.rb
├── dependency_manager_spec.rb
├── generators_spec.rb
├── spec.opts
└── spec_helper.rb
/.document:
--------------------------------------------------------------------------------
1 | README.rdoc
2 | lib/**/*.rb
3 | bin/*
4 | features/**/*.feature
5 | LICENSE
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## MAC OS
2 | .DS_Store
3 |
4 | ## TEXTMATE
5 | *.tmproj
6 | tmtags
7 |
8 | ## EMACS
9 | *~
10 | \#*
11 | .\#*
12 |
13 | ## VIM
14 | *.swp
15 |
16 | ## PROJECT::GENERAL
17 | coverage
18 | rdoc
19 | pkg
20 |
21 | ## PROJECT::SPECIFIC
22 |
23 | spec/tmp/*
24 |
--------------------------------------------------------------------------------
/HISTORY:
--------------------------------------------------------------------------------
1 | == 0.1.3 [08-31-10]
2 | * Add $ choco server command to launch a local rack server
3 | * A config.ru file is created at the root of each new project
4 |
5 | == 0.1.2 [08-27-10]
6 | * Add fixtures generate (mock ajax requests)
7 |
8 | == 0.1.1 [07-27-10]
9 |
10 | * Clean generated HTML (indentation)
11 | * Add lib/application.js file at project generation
12 | * Remove compressed folder
13 | * When a controller is deleted, the watcher script removes it from the app controller
14 | * Add specifications
15 |
16 | == 0.1.0 [07-23-10]
17 |
18 | * Initial release
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 Anthony Heukmes
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.rdoc:
--------------------------------------------------------------------------------
1 | = Choco
2 |
3 | A delicious Javascript web framework made in Belgium!
4 |
5 | Choco brings the MVC to the client side!
6 |
7 | You like Javascript and you want to develop rich internet applications?
8 | You also know that HTML & CSS are powerful?
9 | Cappuccino & Sproutcore don't feel like web development anymore?
10 |
11 | Thanks to Choco, you'll be able to easily develop maintainable web applications.
12 | A Choco app consists of only one HTML page, all the interactions are managed by Javascript.
13 | Your UI only uses HTML and CSS!
14 |
15 | Choco is based on powerful libaries :
16 |
17 | * Sammy (http://github.com/quirkey/sammy)
18 | * js-model (http://github.com/benpickles/js-model)
19 | * Jim (http://github.com/quirkey/jim)
20 |
21 | Huge thanks to Aaron Quint and Ben Pickles for their incredible work.
22 |
23 | A sample project based on Rails 3 is available here : http://github.com/ahe/choco_demo
24 |
25 | An awesome screencast with an awesome belgian accent is available here :
26 | http://www.2dconcept.com/images/choco.mov
27 |
28 | Follow us on Twitter : https://twitter.com/choco_js
29 |
30 | == Installation
31 |
32 | Choco is a Ruby gem, simply install it :
33 |
34 | $ gem install choco
35 |
36 | == A new application
37 |
38 | $ choco new my_project
39 |
40 | This will generate your project structure.
41 |
42 | You can then install the required JS dependencies (jQuery, Sammy, ...) by executing the following command at the root of your project :
43 |
44 | $ rake choco:js:install
45 |
46 | Launch your local server :
47 |
48 | $ choco server
49 |
50 |
51 | == Location
52 |
53 | A Choco app is composed of static files (js, css, images, ...), it must be directly accessible on your web server.
54 |
55 | A local Rack web server can be launched directly using the '$ choco server' command. You'll have to install WEBRick or Mongrel.
56 |
57 | If you use Rails, you can for example put your Choco app inside the public/javascripts folder.
58 |
59 | Once you've chosen the location where your application will reside, don't forget to configure the path to your view files.
60 | You can find the line to edit in your application_controller (app/controllers).
61 |
62 | Example for Rails :
63 |
64 | this.project_path = '/javascripts/my_project';
65 |
66 | == Jim
67 |
68 | Jim is mix of Ruby gems & Bundler but for Javascript libraries.
69 |
70 | When you install a JS library using the $ jim install command, it is stored in your home folder (~/.jim/lib).
71 | All your projects can then use this repository to load the required dependencies.
72 |
73 | The $ rake choco:js:install command installs all the dependencies you need to run a Choco app.
74 |
75 | A Jimfile is located at the root of your project, it lists all these dependencies.
76 | They can be libraries (jQuery, Sammy, ...) but also local JS files of your application (controllers, models, ...).
77 |
78 | All these files are bundled into the compressed/bundled.js file, so you only have to include this file in your HTML page and all your Choco app will be loaded.
79 |
80 | You can continuously track changes in your JS files by running the following command in your project root folder :
81 |
82 | $ choco --watch
83 |
84 | The watch script will track your JS files (creation, edition, suppression) and automatically update your Jimfile & bundled.js to reflect these changes.
85 | You never have to worry about including your JS files inside your HTML page, just include bundled.js!
86 |
87 | == Access your homepage
88 |
89 | To launch your application, just call the index.html page.
90 | I'm using Rails, I will call the following URL in my web browser :
91 | http://localhost:3000/javascripts/choco_app/index.html
92 |
93 | Notice that when the app is launched, the URL changes to :
94 | http://localhost:3000/javascripts/choco_app/index.html#/main
95 |
96 | #/main is a route in your Choco app (thanks to Sammy), it is defined in your ApplicationController.
97 |
98 | this.get('#/main', function(cx) {
99 | });
100 |
101 | You have to include this # in every HTML link you add into your views.
102 |
103 | List all the posts
104 | Add a new post
105 | ...
106 |
107 | = Project structure
108 |
109 | A Choco project has the following structure :
110 |
111 | === Jimfile
112 | This file list all the dependencies for your project (libraries & local files).
113 |
114 | === app
115 | It contains four sub-folders : controllers, helpers, models & views.
116 | This is where you will spend most of your development time.
117 |
118 | === compressed
119 | This is where the bundled.js file is created, it bundles all your JS files in one single file.
120 | It is highly recommended to compress this file before going live (rake choco:deploy).
121 |
122 | === images
123 | Store all the images used by your application in this folder.
124 |
125 | === index.html
126 | This is the file you have to open in your browser to launch your Choco application.
127 | It includes your bundled.js file, your stylesheets and defines the layout of your application.
128 |
129 | The #choco div is very important, this is where the HTML generated by your views will be inserted.
130 | If you change his name, you must configure it into the app/controllers/application_controller.js as well.
131 |
132 | === lib
133 | Use this folder to store your JS files which are specific to your project but don't have their place in the app folder.
134 | If this is a library that can be used by other projects, you should use Jim instead.
135 |
136 | === script
137 | This folder contains the choco script file.
138 | It brings you a few generators (model, controller, layout, scaffold, json, plugin).
139 |
140 | === spec
141 | Test your application using Behavior Driven Development (BDD).
142 |
143 | === stylesheets
144 | Store all the stylesheets used by your application in this folder.
145 |
146 | = A first resource (CRUD)
147 |
148 | First of all, don't forget to start the choco watcher ($ choco --watch) if you don't want to update your Jimfile manually.
149 |
150 | The easiest way to get started is to generate a scaffold based on JSON.
151 | Use your server side technology to create a web service that returns JSON representing your resource.
152 |
153 | For example, with Rails :
154 |
155 | def index
156 | render :json => Post.all
157 | end
158 |
159 | Once you have that, you can generate your scaffold very easily :
160 |
161 | $ choco generate scaffold post http://localhost:3000/posts
162 |
163 | This will create the PostsController with all the actions, the views and the model.
164 |
165 | Notice that the Choco watcher automatically updated your Jimfile and your bundled.js.
166 |
167 | It also updated your ApplicationController by adding the following line :
168 |
169 | PostsController(this);
170 |
171 | You can now call this new page with the following URL :
172 | http://localhost:3000/javascripts/choco_app/index.html#/posts
173 |
174 | This will send a GET request to the #/posts URL of your application.
175 | This request will be handled by your PostsController and more precisely by this action :
176 |
177 | get('#/posts', function(cx) {
178 | cx.posts = Post.all();
179 | });
180 |
181 | We are using our model to get all the posts (locally) and store them in the posts variable.
182 | Using cx will make this variable available in your view.
183 |
184 | Like Rails, Choco will automatically render the view with the same name as the current action (located in the view folder with the same name as the current controller).
185 | In our case app/views/posts/index.template will be rendered.
186 |
187 | This is a simple HTML page with some Javascript tags.
188 |
189 | Here is a part of it :
190 |
191 | <% $.each(posts, function(i, post) { %>
192 |
193 |
194 | <%= post.attr('created_at') %>
195 |
196 |
197 | <%= post.attr('author') %>
198 |
199 | ...
200 |
201 | We are iterating on our posts array to create a table row for each of them.
202 |
203 | You will not see any post yet because you haven't loaded the post from your server (JSON).
204 |
205 | To do that, just update your ApplicationController by adding your Post model in the models array :
206 |
207 | var models = [Post];
208 | ChocoUtils.loadModels(models, function() {
209 | app.run('#/main');
210 | });
211 |
212 | All your models will be loaded by calling the load() method on their class.
213 | This action will send Ajax requests to your server.
214 | The Choco application will then be launched when all the responses have been received and treated.
215 |
216 | To create, remove & update posts, you have to create your REST controller on the server side.
217 | Have a look at the sample demo for an example (http://github.com/ahe/choco_demo).
218 |
219 | You can also use fixtures instead. Fixtures are located in the /fixtures folder, they use the jquery.mockjax plugin to mock Ajax requests and return the JSON you defined in your fixtures.
220 |
221 | Use the choco generate fixture command to easily create your fixtures (e.g : $ choco generate fixture post, will mock requests sent to the /posts URL).
222 |
223 | = Generators
224 |
225 | The following code generators are available :
226 |
227 | * $ choco generate controller
228 | * $ choco generate model
229 | * $ choco generate scaffold [field1 field2 ...]
230 | * $ choco generate scaffold
231 | * $ choco generate fixture
232 | * $ choco generate layout
233 | * $ choco generate plugin
234 |
235 | Don't forget to start the choco --watch command before executing any generator. Otherwise you'll have to update manually your Jimfile, bundled.js & application_controller.js.
236 |
237 | = Controllers
238 |
239 | To learn more about controllers, please read Sammy documentation : http://code.quirkey.com/sammy
240 |
241 | You may be wondering about the best solution to execute Javascript code after rendering a template.
242 | Let's say we want to add a specific behavior to one of our link, in the app/views/posts/index.template view, I add this simple link :
243 |
244 | Hey, click me, I'm a simple test!
245 |
246 | I want to open a Javascript alert when it is clicked.
247 |
248 | I can simply update my controller like this :
249 |
250 | get('#/posts', function(cx) {
251 | cx.posts = Post.all();
252 | cx.render({ template: 'posts/index', event: 'posts_loaded', data: { size: cx.posts.length }});
253 | });
254 |
255 | bind('posts_loaded', function(e, data) {
256 | $('#test_link').click(function() {
257 | alert('Hey! We have ' + data['size'] + ' posts!');
258 | return false;
259 | });
260 | });
261 |
262 | I call the render() method explicitly because I want to trigger an event when the template is rendered.
263 | This event is named 'posts_loaded' and when it is executed it simply add a Javascript behavior to my link.
264 |
265 | The render method supports various options like like layouts, events & more.
266 | You can read the doc here : http://github.com/ahe/choco.libs/blob/master/plugins/sammy/choco.plugins.sammy.smart_renderer.js
267 |
268 | = Views
269 |
270 | By default, Choco uses simple template views where you can combine HTML and Javascript.
271 |
272 | You can easily display values in your views :
273 |
274 | <%= post.attr('title') %>
275 |
276 | Or call helpers you defined :
277 |
278 | <% myHelper(); %> // Don't forget the ;
279 |
280 | You can also of course use conditions, iterators & more.
281 |
282 | You can easily switch to HAML or Mustache by configuring it in your application controller.
283 | Have a look at Sammy documentation for more information.
284 |
285 | To create a DELETE link, just use the following attributes :
286 |
287 | Delete
288 |
289 | = Models
290 |
291 | For more information about models, please read js-model documentation : http://github.com/benpickles/js-model
292 |
293 | js-model stores all the data locally. You can persist your models to the server using methods like save() but don't forget to implement your REST controller on the server side.
294 | Have a look at the demo for an example : http://github.com/ahe/choco_demo
295 |
296 | js-model expects JSON without the ROOT element included. In Rails that means you have to disable this option :
297 |
298 | ActiveRecord::Base.include_root_in_json = false
299 |
300 | = Logger
301 |
302 | You can call the logger from anywhere in your application by simply calling :
303 |
304 | app.logger('hello choco!');
305 |
306 | = Plugins
307 |
308 | Models, views & controllers can easily be extended using plugins.
309 |
310 | You can generate a new plugin using the following command :
311 |
312 | $ choco generate plugin
313 |
314 | Existing plugins & Choco libs are stored here : http://github.com/ahe/choco.libs
315 |
316 | = Deploy
317 |
318 | When you deploy your application on live, don't forget to compress your files :
319 |
320 | $ rake choco:deploy
321 |
322 | Then just copy the required files on your web server.
323 |
324 | = BDD
325 |
326 | BDD is currently being implemented, it will be soon very easy to test all the parts of your Choco apps.
327 | A first solution can be found here : http://github.com/ahe/sammy_demo/tree/master/test/javascript
328 |
329 | = Mailing list
330 |
331 | http://groups.google.com/group/choco-js
332 |
333 | = Note on Patches/Pull Requests
334 |
335 | * Fork the project.
336 | * Make your feature addition or bug fix.
337 | * Add tests for it. This is important so I don't break it in a
338 | future version unintentionally.
339 | * Commit, do not mess with rakefile, version, or history.
340 | (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
341 | * Send me a pull request. Bonus points for topic branches.
342 |
343 | = Copyright
344 |
345 | Copyright (c) 2010 Anthony Heukmes. See LICENSE for details.
346 |
347 | * http://2dconcept.com
348 | * http://intotheweb.be
349 | * http://twitter.com/2dc
350 | * http://twitter.com/intotheweb
351 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'rake'
3 |
4 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
5 |
6 | require 'choco'
7 |
8 | begin
9 | require 'jeweler'
10 | Jeweler::Tasks.new do |gem|
11 | gem.name = "choco"
12 | gem.version = Choco::VERSION
13 | gem.summary = %Q{A delicious Javascript web framework made in Belgium!}
14 | gem.description = %Q{Choco brings the MVC to the client side! It allows you to easily develop maintainable Rich Internet Applications using Javascript.}
15 | gem.email = "anthony.heukmes@skynet.be"
16 | gem.homepage = "http://github.com/ahe/choco"
17 | gem.authors = ["Anthony Heukmes"]
18 |
19 | gem.add_dependency "jim"
20 | gem.add_dependency "fssm"
21 | gem.add_dependency "thor"
22 | gem.add_dependency "activesupport"
23 | gem.add_dependency "rack"
24 |
25 | gem.add_development_dependency "rspec", ">= 1.2.9"
26 | end
27 | Jeweler::GemcutterTasks.new
28 | rescue LoadError
29 | puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
30 | end
31 |
32 | require 'spec/rake/spectask'
33 | Spec::Rake::SpecTask.new(:spec) do |spec|
34 | spec.libs << 'lib' << 'spec'
35 | spec.spec_files = FileList['spec/**/*_spec.rb']
36 | end
37 |
38 | Spec::Rake::SpecTask.new(:rcov) do |spec|
39 | spec.libs << 'lib' << 'spec'
40 | spec.pattern = 'spec/**/*_spec.rb'
41 | spec.rcov = true
42 | end
43 |
44 | task :spec => :check_dependencies
45 |
46 | task :default => :spec
47 |
48 | require 'rake/rdoctask'
49 | Rake::RDocTask.new do |rdoc|
50 | version = File.exist?('VERSION') ? File.read('VERSION') : ""
51 |
52 | rdoc.rdoc_dir = 'rdoc'
53 | rdoc.title = "choco #{version}"
54 | rdoc.rdoc_files.include('README*')
55 | rdoc.rdoc_files.include('lib/**/*.rb')
56 | end
57 |
--------------------------------------------------------------------------------
/bin/choco:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'choco'
4 | require 'pathname'
5 |
6 | module Choco
7 | module ScriptChocoLoader
8 | SCRIPT_CHOCO = File.join('script', 'choco')
9 |
10 | def self.exec_script_choco!
11 | cwd = Dir.pwd
12 | exec 'ruby', SCRIPT_CHOCO, *ARGV if in_choco_application?
13 |
14 | Dir.chdir("..") do
15 | # Recurse in a chdir block: if the search fails we want to be sure
16 | # the application is generated in the original working directory.
17 | exec_script_choco! unless cwd == Dir.pwd
18 | end
19 | rescue SystemCallError
20 | # could not chdir, no problem just return
21 | end
22 |
23 | def self.in_choco_application?
24 | File.exists?(SCRIPT_CHOCO) || in_choco_application_subdirectory?
25 | end
26 |
27 | def self.in_choco_application_subdirectory?(path = Pathname.new(Dir.pwd))
28 | File.exists?(File.join(path, SCRIPT_CHOCO)) || !path.root? && in_choco_application_subdirectory?(path.parent)
29 | end
30 | end
31 | end
32 |
33 | Choco::ScriptChocoLoader.exec_script_choco!
34 |
35 | ARGV << '--help' if ARGV.empty?
36 | command = ARGV.shift
37 |
38 | case command
39 | when 'new'
40 | Choco::AppGenerator.start ARGV
41 | when '-v'
42 | puts "Choco version #{Choco::VERSION}"
43 | else
44 | puts "\nWelcome to Choco!\nA delicious Javascript web framework made in Belgium!\n\nUsage:\n\n$ choco new \n-> Generates a new Choco project\n\n$ choco -v\n-> Displays current version\n"
45 | end
--------------------------------------------------------------------------------
/choco.gemspec:
--------------------------------------------------------------------------------
1 | # Generated by jeweler
2 | # DO NOT EDIT THIS FILE DIRECTLY
3 | # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4 | # -*- encoding: utf-8 -*-
5 |
6 | Gem::Specification.new do |s|
7 | s.name = %q{choco}
8 | s.version = "0.1.3"
9 |
10 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11 | s.authors = ["Anthony Heukmes"]
12 | s.date = %q{2010-08-09}
13 | s.default_executable = %q{choco}
14 | s.description = %q{Choco brings the MVC to the client side! It allows you to easily develop maintainable Rich Internet Applications using Javascript.}
15 | s.email = %q{anthony.heukmes@skynet.be}
16 | s.executables = ["choco"]
17 | s.extra_rdoc_files = [
18 | "LICENSE",
19 | "README.rdoc"
20 | ]
21 | s.files = [
22 | ".document",
23 | ".gitignore",
24 | "HISTORY",
25 | "LICENSE",
26 | "README.rdoc",
27 | "Rakefile",
28 | "bin/choco",
29 | "choco.gemspec",
30 | "lib/choco.rb",
31 | "lib/choco/cli.rb",
32 | "lib/choco/dependency_manager.rb",
33 | "lib/choco/generators/app_generator.rb",
34 | "lib/choco/generators/controller_generator.rb",
35 | "lib/choco/generators/fixture_generator.rb",
36 | "lib/choco/generators/layout_generator.rb",
37 | "lib/choco/generators/model_generator.rb",
38 | "lib/choco/generators/plugin_generator.rb",
39 | "lib/choco/generators/scaffold_generator.rb",
40 | "lib/choco/generators/templates/Jimfile",
41 | "lib/choco/generators/templates/README.rdoc",
42 | "lib/choco/generators/templates/Rakefile",
43 | "lib/choco/generators/templates/application.css",
44 | "lib/choco/generators/templates/choco",
45 | "lib/choco/generators/templates/config.ru",
46 | "lib/choco/generators/templates/controllers/application_controller.js",
47 | "lib/choco/generators/templates/controllers/base_controller.js",
48 | "lib/choco/generators/templates/controllers/rest_controller.js",
49 | "lib/choco/generators/templates/fixtures/base.js",
50 | "lib/choco/generators/templates/fixtures/model/array.js",
51 | "lib/choco/generators/templates/help/commands",
52 | "lib/choco/generators/templates/help/generators",
53 | "lib/choco/generators/templates/helpers/application_helper.js",
54 | "lib/choco/generators/templates/index.html",
55 | "lib/choco/generators/templates/lib/application.js",
56 | "lib/choco/generators/templates/lib/plugin.js",
57 | "lib/choco/generators/templates/models/base.js",
58 | "lib/choco/generators/templates/views/edit.template",
59 | "lib/choco/generators/templates/views/index.template",
60 | "lib/choco/generators/templates/views/layout.js",
61 | "lib/choco/generators/templates/views/main/index.template",
62 | "lib/choco/generators/templates/views/new.template",
63 | "lib/choco/generators/templates/views/show.template",
64 | "spec/choco_spec.rb",
65 | "spec/dependency_manager_spec.rb",
66 | "spec/generators_spec.rb",
67 | "spec/spec.opts",
68 | "spec/spec_helper.rb"
69 | ]
70 | s.homepage = %q{http://github.com/ahe/choco}
71 | s.rdoc_options = ["--charset=UTF-8"]
72 | s.require_paths = ["lib"]
73 | s.rubygems_version = %q{1.3.6}
74 | s.summary = %q{A delicious Javascript web framework made in Belgium!}
75 | s.test_files = [
76 | "spec/choco_spec.rb",
77 | "spec/dependency_manager_spec.rb",
78 | "spec/generators_spec.rb",
79 | "spec/spec_helper.rb"
80 | ]
81 |
82 | if s.respond_to? :specification_version then
83 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
84 | s.specification_version = 3
85 |
86 | if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
87 | s.add_runtime_dependency(%q, [">= 0"])
88 | s.add_runtime_dependency(%q, [">= 0"])
89 | s.add_runtime_dependency(%q, [">= 0"])
90 | s.add_runtime_dependency(%q, [">= 0"])
91 | s.add_runtime_dependency(%q, [">= 0"])
92 | s.add_development_dependency(%q, [">= 1.2.9"])
93 | else
94 | s.add_dependency(%q, [">= 0"])
95 | s.add_dependency(%q, [">= 0"])
96 | s.add_dependency(%q, [">= 0"])
97 | s.add_dependency(%q, [">= 0"])
98 | s.add_dependency(%q, [">= 0"])
99 | s.add_dependency(%q, [">= 1.2.9"])
100 | end
101 | else
102 | s.add_dependency(%q, [">= 0"])
103 | s.add_dependency(%q, [">= 0"])
104 | s.add_dependency(%q, [">= 0"])
105 | s.add_dependency(%q, [">= 0"])
106 | s.add_dependency(%q, [">= 0"])
107 | s.add_dependency(%q, [">= 1.2.9"])
108 | end
109 | end
110 |
111 |
--------------------------------------------------------------------------------
/lib/choco.rb:
--------------------------------------------------------------------------------
1 | require 'thor'
2 | require 'thor/group'
3 | require 'active_support/inflector'
4 |
5 | module Choco
6 | VERSION = '0.1.3'
7 |
8 | autoload :DependencyManager, 'choco/dependency_manager'
9 | autoload :CLI, 'choco/cli'
10 | autoload :AppGenerator, 'choco/generators/app_generator'
11 | autoload :ControllerGenerator, 'choco/generators/controller_generator'
12 | autoload :LayoutGenerator, 'choco/generators/layout_generator'
13 | autoload :FixtureGenerator, 'choco/generators/fixture_generator'
14 | autoload :ModelGenerator, 'choco/generators/model_generator'
15 | autoload :PluginGenerator, 'choco/generators/plugin_generator'
16 | autoload :ScaffoldGenerator, 'choco/generators/scaffold_generator'
17 | end
--------------------------------------------------------------------------------
/lib/choco/cli.rb:
--------------------------------------------------------------------------------
1 | require 'pathname'
2 |
3 | module Choco
4 |
5 | class CLI
6 |
7 | def initialize(args)
8 | @args = args
9 | @output = ""
10 | end
11 |
12 | def run
13 | @args << '--help' if @args.empty?
14 |
15 | aliases = {
16 | "g" => "generate",
17 | "s" => "server"
18 | }
19 |
20 | command = @args.shift
21 | command = aliases[command] || command
22 |
23 | case command
24 | when 'generate'
25 | name = @args.shift
26 | if name
27 | klass = eval("Choco::#{name.capitalize}Generator")
28 | klass.start @args
29 | else
30 | @output = template('generators')
31 | end
32 |
33 | when 'server'
34 | port = 9292
35 | port = @args[@args.index('-p') + 1] if @args.include?('-p')
36 | port = @args[@args.index('--port') + 1] if @args.include?('--port')
37 | puts "*** Choco server is now running on port #{port}"
38 | puts "*** Launch http://localhost:#{port}/index.html to start your Choco application"
39 | system "rackup #{@args.join(' ')}"
40 |
41 | when '--watch'
42 | require 'fssm'
43 |
44 | puts "*** Choco is now watching your JS files..."
45 |
46 | system "jim bundle #{Choco::DependencyManager.to}"
47 |
48 | FSSM.monitor(Dir.pwd, ['**/*.js', 'Jimfile']) do
49 | update do |base, relative|
50 | unless relative.include?('bundled.js')
51 | puts "*** #{relative} changed!"
52 | system "jim bundle #{Choco::DependencyManager.to}"
53 | end
54 | end
55 |
56 | create do |base, relative|
57 | unless relative.include?('bundled.js')
58 | puts "*** #{relative} created!"
59 | Choco::DependencyManager.add_dependency(relative)
60 | system "jim bundle #{Choco::DependencyManager.to}"
61 | end
62 | end
63 |
64 | delete do |base, relative|
65 | puts "*** #{relative} deleted!"
66 | Choco::DependencyManager.remove_dependency(relative)
67 | system "jim bundle #{Choco::DependencyManager.to}"
68 | end
69 | end
70 | else
71 | @output = template('commands')
72 | end
73 |
74 | @output
75 | end
76 |
77 | private
78 |
79 | def template(path)
80 | (Pathname.new(__FILE__).dirname + 'generators/templates/help/' + path).read
81 | end
82 |
83 | end
84 | end
--------------------------------------------------------------------------------
/lib/choco/dependency_manager.rb:
--------------------------------------------------------------------------------
1 | module Choco
2 | class DependencyManager
3 |
4 | @@to = 'lib/bundled.js'
5 |
6 | def self.to
7 | @@to
8 | end
9 |
10 | def self.add_dependency(filename)
11 | filename = remove_extension(filename)
12 | type = get_file_type(filename)
13 |
14 | already_present = false
15 | File.new('Jimfile', "r").each do |line|
16 | if line.include?(filename)
17 | already_present = true
18 | break
19 | end
20 | end
21 |
22 | unless already_present
23 | jimfile = ""
24 | File.new('Jimfile', "r").each do |line|
25 | jimfile << line
26 | if line.include?("// #{type}")
27 | jimfile << "#{filename}\n"
28 | end
29 | end
30 |
31 | File.open('Jimfile', "wb") { |io| io.print jimfile }
32 |
33 | if type == 'Controller' || type == 'Helper'
34 | application_controller = ""
35 | file = extract_filename(filename)
36 |
37 | File.new('app/controllers/application_controller.js', "r").each do |line|
38 | application_controller << line
39 | if line.include?("/* Configure your #{type.downcase.pluralize} here")
40 | if type == 'Helper'
41 | application_controller << "\tthis.helpers(#{file});\n"
42 | else
43 | application_controller << "\t#{file}(this);\n"
44 | end
45 | end
46 | end
47 |
48 | File.open('app/controllers/application_controller.js', "wb") { |io| io.print application_controller }
49 | end
50 | end
51 | end
52 |
53 | def self.remove_dependency(filename)
54 | filename = remove_extension(filename)
55 | type = get_file_type(filename)
56 |
57 | jimfile = ""
58 | File.new('Jimfile', "r").each do |line|
59 | jimfile << line unless line.include?(filename)
60 | end
61 |
62 | File.open('Jimfile', "wb") { |io| io.print jimfile }
63 |
64 | file = extract_filename(filename)
65 | application_controller = ""
66 | File.new('app/controllers/application_controller.js', "r").each do |line|
67 | if type == 'Model'
68 | application_controller << line
69 | elsif !line.include?(file)
70 | application_controller << line
71 | end
72 | end
73 |
74 | File.open('app/controllers/application_controller.js', "wb") { |io| io.print application_controller }
75 | end
76 |
77 | private
78 |
79 | def self.remove_extension(filename)
80 | filename.gsub('.js', '')
81 | end
82 |
83 | def self.extract_filename(filename)
84 | filename.to_s.split('/').last.camelcase
85 | end
86 |
87 | def self.get_file_type(filename)
88 | if filename.include?('controllers/')
89 | 'Controller'
90 | elsif filename.include?('helpers/')
91 | 'Helper'
92 | elsif filename.include?('models/')
93 | 'Model'
94 | elsif filename.include?('fixtures/')
95 | 'Fixture'
96 | else
97 | 'Libs'
98 | end
99 | end
100 | end
101 | end
--------------------------------------------------------------------------------
/lib/choco/generators/app_generator.rb:
--------------------------------------------------------------------------------
1 | module Choco
2 | class AppGenerator < Thor::Group
3 | include Thor::Actions
4 |
5 | def self.source_root
6 | File.dirname(__FILE__)
7 | end
8 |
9 | desc 'Generates a delicious Choco app'
10 | argument :name
11 |
12 | def create_root_folder
13 | empty_directory name
14 | end
15 |
16 | def create_app_folder
17 | empty_directory "#{name}/app"
18 | empty_directory "#{name}/app/controllers"
19 | empty_directory "#{name}/app/models"
20 | empty_directory "#{name}/app/views"
21 | empty_directory "#{name}/app/views/main"
22 | empty_directory "#{name}/app/views/layouts"
23 | empty_directory "#{name}/app/helpers"
24 |
25 | template('templates/controllers/application_controller.js', "#{name}/app/controllers/application_controller.js")
26 | template('templates/views/main/index.template', "#{name}/app/views/main/index.template")
27 | template('templates/helpers/application_helper.js', "#{name}/app/helpers/application_helper.js")
28 | end
29 |
30 | def create_lib_folder
31 | empty_directory "#{name}/lib"
32 | template("templates/lib/application.js", "#{name}/lib/application.js")
33 | end
34 |
35 | def create_images_folder
36 | empty_directory "#{name}/images"
37 | end
38 |
39 | def create_stylesheets_folder
40 | empty_directory "#{name}/stylesheets"
41 | template('templates/application.css', "#{name}/stylesheets/application.css")
42 | end
43 |
44 | def create_fixtures_folder
45 | empty_directory "#{name}/fixtures"
46 | end
47 |
48 | def create_spec_folder
49 | empty_directory "#{name}/spec"
50 | end
51 |
52 | def create_script_folder
53 | empty_directory "#{name}/script"
54 | template('templates/choco', "#{name}/script/choco")
55 | end
56 |
57 | def create_jimfile
58 | template('templates/Jimfile', "#{name}/Jimfile")
59 | end
60 |
61 | def create_rakefile
62 | template('templates/Rakefile', "#{name}/Rakefile")
63 | end
64 |
65 | def create_rackup_file
66 | template('templates/config.ru', "#{name}/config.ru")
67 | end
68 |
69 | def create_readme_file
70 | create_file "#{name}/README.rdoc"
71 | end
72 |
73 | def create_index_file
74 | template('templates/index.html', "#{name}/index.html")
75 | end
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/lib/choco/generators/controller_generator.rb:
--------------------------------------------------------------------------------
1 | module Choco
2 | class ControllerGenerator < Thor::Group
3 | include Thor::Actions
4 |
5 | def self.source_root
6 | File.dirname(__FILE__)
7 | end
8 |
9 | desc 'Generates a Choco controller'
10 | argument :name
11 |
12 | def create_controller_file
13 | template('templates/controllers/base_controller.js', "app/controllers/#{name.underscore}_controller.js")
14 | end
15 |
16 | def create_views_folder
17 | empty_directory "app/views/#{name.underscore}"
18 | end
19 |
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/choco/generators/fixture_generator.rb:
--------------------------------------------------------------------------------
1 | module Choco
2 | class FixtureGenerator < Thor::Group
3 | include Thor::Actions
4 |
5 | def self.source_root
6 | File.dirname(__FILE__)
7 | end
8 |
9 | desc 'Generates Ajax fixtures (mocks)'
10 | argument :name, :required => true
11 |
12 | def create_mock_file
13 | @name = name.underscore.pluralize
14 | template('templates/fixtures/base.js', "fixtures/#{@name}.js")
15 | end
16 |
17 | def create_json_folder
18 | empty_directory "fixtures/#{@name}"
19 | template('templates/fixtures/model/array.js', "fixtures/#{@name}/#{@name}.json")
20 | end
21 |
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/lib/choco/generators/layout_generator.rb:
--------------------------------------------------------------------------------
1 | module Choco
2 | class LayoutGenerator < Thor::Group
3 | include Thor::Actions
4 |
5 | def self.source_root
6 | File.dirname(__FILE__)
7 | end
8 |
9 | desc 'Generates a Choco layout'
10 | argument :name
11 |
12 | def create_model_file
13 | @layout_name = name.camelcase.singularize
14 | @name = name.underscore.singularize
15 | template('templates/views/layout.js', "app/views/layouts/#{@name}.js")
16 | end
17 |
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/choco/generators/model_generator.rb:
--------------------------------------------------------------------------------
1 | module Choco
2 | class ModelGenerator < Thor::Group
3 | include Thor::Actions
4 |
5 | def self.source_root
6 | File.dirname(__FILE__)
7 | end
8 |
9 | desc 'Generates a Choco model'
10 | argument :name
11 |
12 | def create_model_file
13 | @model_name = name.camelcase.singularize
14 | @model = name.underscore.singularize
15 | @route_path = name.underscore.pluralize
16 | template('templates/models/base.js', "app/models/#{@model}.js")
17 | end
18 |
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/choco/generators/plugin_generator.rb:
--------------------------------------------------------------------------------
1 | module Choco
2 | class PluginGenerator < Thor::Group
3 | include Thor::Actions
4 |
5 | def self.source_root
6 | File.dirname(__FILE__)
7 | end
8 |
9 | desc 'Generates a Choco plugin (Sammy or js-model)'
10 | argument :name
11 | class_option :for_lib
12 |
13 | def create_model_file
14 | @plugin_name = name.camelcase.singularize
15 | @name = name.underscore.singularize
16 | template('templates/lib/plugin.js', "lib/plugin_#{@name}.js")
17 | end
18 |
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/choco/generators/scaffold_generator.rb:
--------------------------------------------------------------------------------
1 | require 'open-uri'
2 | require 'json'
3 |
4 | module Choco
5 | class ScaffoldGenerator < Thor::Group
6 | include Thor::Actions
7 |
8 | attr_accessor :keys
9 |
10 | def self.source_root
11 | File.dirname(__FILE__)
12 | end
13 |
14 | desc 'Generates a Choco CRUD controller with views & model'
15 | argument :name, :required => true
16 | argument :fields, :type => :array, :default => []
17 |
18 | def get_data_structure
19 | @controller_name = name.pluralize.camelcase
20 | @route_path = name.pluralize.underscore
21 | @model = name.singularize.underscore
22 | @model_name = name.singularize.camelcase
23 |
24 | @keys = []
25 | if fields.first && fields.first.include?('http://')
26 | @keys = load_json(fields.first)
27 | else
28 | @keys = fields
29 | end
30 | end
31 |
32 | def create_controller
33 | template('templates/controllers/rest_controller.js', "app/controllers/#{@route_path}_controller.js")
34 | end
35 |
36 | def create_views
37 | empty_directory "app/views/#{@route_path}"
38 | template('templates/views/index.template', "app/views/#{@route_path}/index.template")
39 | template('templates/views/show.template', "app/views/#{@route_path}/show.template")
40 | template('templates/views/new.template', "app/views/#{@route_path}/new.template")
41 | template('templates/views/edit.template', "app/views/#{@route_path}/edit.template")
42 | end
43 |
44 | def create_model
45 | template('templates/models/base.js', "app/models/#{@model}.js")
46 | end
47 |
48 | private
49 |
50 | def load_json(url)
51 | begin
52 | buffer = open(url, 'UserAgent' => 'Choco').read
53 | data = JSON.parse(buffer)[0]
54 |
55 | if data.size == 1 && data.first[1].is_a?(Hash)
56 | data = data.first[1]
57 | end
58 |
59 | keys = data.map{ |key, value| key }
60 | rescue Exception
61 | puts "An error occured (check that your URL is reachable and that your JSON is not empty)"
62 | end
63 | keys
64 | end
65 |
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/lib/choco/generators/templates/Jimfile:
--------------------------------------------------------------------------------
1 | // Your Jimfile lists your JS dependencies
2 | // Launch $ choco --watch at the root of your project
3 | // This file and lib/bundled.js will be maintained for you!
4 |
5 | jquery
6 | sammy
7 | sammy.template
8 | sammy.nested_params
9 | sammy.smart_renderer
10 | js-model 0.8.3
11 | underscore
12 | mustache
13 | jquery.mockjax
14 | choco.utils
15 | choco.plugins.models.load
16 |
17 | // Libs # Don't remove this line!
18 | lib/application
19 |
20 | // Helpers # Don't remove this line!
21 | app/helpers/application_helper
22 |
23 | // Models # Don't remove this line!
24 |
25 | // Controllers # Don't remove this line!
26 | app/controllers/application_controller
27 |
28 | // Fixtures # Don't remove this line!
29 |
--------------------------------------------------------------------------------
/lib/choco/generators/templates/README.rdoc:
--------------------------------------------------------------------------------
1 | == Welcome to Choco
2 |
3 | A delicious Javascript web framework made in Belgium!
--------------------------------------------------------------------------------
/lib/choco/generators/templates/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rake'
2 |
3 | namespace :choco do
4 |
5 | namespace :js do
6 |
7 | desc "Install Javascript dependencies"
8 | task :install do
9 | system 'jim install http://code.jquery.com/jquery-1.4.2.js'
10 | system 'jim install http://github.com/quirkey/sammy/zipball/v0.5.4'
11 | system 'jim install http://github.com/benpickles/js-model/zipball/v0.8.4'
12 | system 'jim install http://documentcloud.github.com/underscore/underscore.js'
13 | system 'jim install http://github.com/janl/mustache.js/zipball/0.2.3'
14 | system 'jim install http://github.com/ahe/choco.libs/raw/master/choco.utils.js'
15 | system 'jim install http://github.com/ahe/choco.libs/raw/master/plugins/models/choco.plugins.models.load.js'
16 | system 'jim install http://github.com/ahe/choco.libs/raw/master/plugins/sammy/choco.plugins.sammy.smart_renderer.js'
17 | system 'jim install http://github.com/appendto/jquery-mockjax/raw/master/jquery.mockjax.js'
18 | system 'jim bundle lib/bundled.js'
19 | end
20 | end
21 |
22 | desc "Compress all your JS files into lib/compressed.js"
23 | task :deploy do
24 | system 'jim compress lib/compressed.js'
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/choco/generators/templates/application.css:
--------------------------------------------------------------------------------
1 | @import url(http://yui.yahooapis.com/3.0.0/build/cssreset/reset-min.css);
--------------------------------------------------------------------------------
/lib/choco/generators/templates/choco:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'rubygems'
4 | require 'choco'
5 |
6 | cli = Choco::CLI.new(ARGV)
7 | puts cli.run
--------------------------------------------------------------------------------
/lib/choco/generators/templates/config.ru:
--------------------------------------------------------------------------------
1 | map '/' do
2 | run Rack::Directory.new('.')
3 | end
--------------------------------------------------------------------------------
/lib/choco/generators/templates/controllers/application_controller.js:
--------------------------------------------------------------------------------
1 | var app = $.sammy(function() {
2 |
3 | this.element_selector = '#choco';
4 | this.template_engine = 'template';
5 | this.project_path = '';
6 | this.fixtures = true;
7 |
8 | // Configure your Sammy JS plugins
9 | this.use(Sammy.Template);
10 | this.use(Sammy.NestedParams);
11 | this.use(Sammy.SmartRenderer, this.project_path + '/app/views/');
12 |
13 | // Event fired by the render() method
14 | this.bind('template_loaded', function(e, data) {
15 | ChocoUtils.activateDeleteLinks(app);
16 | });
17 |
18 | // Root page
19 | this.get('#/main', function(cx) {
20 | });
21 |
22 | /* Configure your helpers here */
23 | this.helpers(ApplicationHelper);
24 |
25 | /* Configure your controllers here ### Don't remove this line! */
26 | // PostsController(this);
27 | });
28 |
29 | $(function() {
30 | // Load your models here, example : var models = [Post, Category]
31 | var models = [];
32 | ChocoUtils.loadModels(models, function() {
33 | app.run('#/main');
34 | });
35 | });
--------------------------------------------------------------------------------
/lib/choco/generators/templates/controllers/base_controller.js:
--------------------------------------------------------------------------------
1 | <%= name.camelcase %>Controller = function(app) { with(app) {
2 |
3 | get('#/<%= name.underscore %>', function(cx) {
4 | });
5 |
6 | }};
--------------------------------------------------------------------------------
/lib/choco/generators/templates/controllers/rest_controller.js:
--------------------------------------------------------------------------------
1 | <%= @controller_name %>Controller = function(app) { with(app) {
2 |
3 | /** Routes **/
4 |
5 | // GET index
6 | get('#/<%= @route_path %>', function(cx) {
7 | cx.<%= @model.pluralize %> = <%= @model_name %>.all();
8 | });
9 |
10 | // GET new
11 | get('#/<%= @route_path %>/new', function(cx) {
12 | });
13 |
14 | // POST create
15 | post('#/<%= @route_path %>', function(cx) {
16 | var <%= @model %> = new <%= @model_name %>(cx.params['<%= @model %>']);
17 | <%= @model %>.save(function(success) {
18 | cx.redirect('#/<%= @route_path %>/' + <%= @model %>.id());
19 | });
20 | });
21 |
22 | // GET edit
23 | get('#/<%= @route_path %>/edit/:id', function(cx) {
24 | cx.<%= @model %> = <%= @model_name %>.find(cx.params['id']);
25 | });
26 |
27 | // PUT update
28 | put('#/<%= @route_path %>/update/:id', function(cx) {
29 | var <%= @model %> = <%= @model_name %>.find(cx.params['id']);
30 | <%= @model %>.update(cx.params['<%= @model %>']).save(function(success) {
31 | cx.redirect('#/<%= @route_path %>/' + <%= @model %>.id())
32 | });
33 | });
34 |
35 | // DELETE destroy
36 | route('delete', '#/<%= @route_path %>/:id', function(cx) {
37 | var <%= @model %> = <%= @model_name %>.find(cx.params['id']);
38 | <%= @model %>.destroy();
39 | cx.trigger('<%= @model %>_remove', { <%= @model %>_id: <%= @model %>.id() });
40 | });
41 |
42 | // GET show
43 | get('#/<%= @route_path %>/:id', function(cx) {
44 | cx.<%= @model %> = <%= @model_name %>.find(cx.params['id']);
45 | });
46 |
47 | /** Events **/
48 |
49 | bind('<%= @model %>_remove', function(e, data) {
50 | $('#<%= @model %>_' + data['<%= @model %>_id']).remove();
51 | });
52 |
53 | }};
--------------------------------------------------------------------------------
/lib/choco/generators/templates/fixtures/base.js:
--------------------------------------------------------------------------------
1 | if(app.fixtures) {
2 | var model = '{ "id": 1, "title": "Hello Choco!" }';
3 |
4 | $.mockjax({
5 | url: '/<%= @name %>/*',
6 | responseText: model
7 | });
8 |
9 | $.mockjax({
10 | url: '/<%= @name %>',
11 | type: 'POST',
12 | responseText: model
13 | });
14 |
15 | $.mockjax({
16 | url: '/<%= @name %>',
17 | type: 'GET',
18 | proxy: app.project_path + '/fixtures/<%= @name %>/<%= @name %>.json'
19 | });
20 | }
--------------------------------------------------------------------------------
/lib/choco/generators/templates/fixtures/model/array.js:
--------------------------------------------------------------------------------
1 | [
2 | { "id": 1, "title": "Hello Choco!" },
3 | { "id": 2, "title": "Hello Sammy!" }
4 | ]
--------------------------------------------------------------------------------
/lib/choco/generators/templates/help/commands:
--------------------------------------------------------------------------------
1 |
2 | The choco script responds to the following commands and options :
3 |
4 | --watch
5 | The Choco watch command will track JS files in your project (create, update, remove).
6 | It will regenerate your bundled.js at every modification in one of your JS files.
7 | Your Jimfile will also be maintained by this command.
8 |
9 | generate [options]
10 | Available generators are : controller, model, scaffold, fixture, layout, plugin
11 | Run '$ choco generate', for more information.
12 |
13 | server [options]
14 | -s, --server SERVER serve using SERVER (webrick/mongrel)
15 | -p, --port PORT use PORT (default: 9292)
16 |
17 |
--------------------------------------------------------------------------------
/lib/choco/generators/templates/help/generators:
--------------------------------------------------------------------------------
1 |
2 | The following Choco generators are available :
3 |
4 | controller
5 | $ choco generate controller
6 |
7 | It will create the controller file and a views folder.
8 |
9 | model
10 | $ choco generate model
11 |
12 | It will create the model file.
13 |
14 | scaffold
15 | $ choco generate scaffold [field1 field2 ...]
16 |
17 | It will create a RESTful controller, the model and the views.
18 |
19 | scaffold
20 | $ choco generate scaffold
21 |
22 | It will create a RESTful controller, the model and the views.
23 | The fields will be determined from the JSON returned by your URL
24 | e.g : http://localhost:3000/posts.json
25 |
26 | fixture
27 | $ choco generate fixture
28 |
29 | It will create fixture & JSON files.
30 | resource_name will be pluralized.
31 |
32 | $ choco generate fixture post
33 | Will mock requests sent to /posts
34 |
35 | layout
36 | $ choco generate layout
37 |
38 | It will create the layout file.
39 |
40 | plugin
41 | $ choco generate plugin
42 |
43 |
--------------------------------------------------------------------------------
/lib/choco/generators/templates/helpers/application_helper.js:
--------------------------------------------------------------------------------
1 | // Helpers are available in your controllers and your views
2 |
3 | var ApplicationHelper = {
4 | helloWorld: function() {
5 | alert("Hello World!");
6 | }
7 | }
--------------------------------------------------------------------------------
/lib/choco/generators/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/lib/choco/generators/templates/lib/application.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 |
3 | });
--------------------------------------------------------------------------------
/lib/choco/generators/templates/lib/plugin.js:
--------------------------------------------------------------------------------
1 | // js-model plugin
2 | // It allows you to add methods to all your models.
3 |
4 | var <%= @plugin_name %>Plugin = {
5 | modelsClassMethods : {
6 | myhelper: function() {
7 | alert('hello world [class method]');
8 | }
9 | },
10 |
11 | modelsInstanceMethods : {
12 | myhelper: function() {
13 | alert('hello world [instance method]');
14 | }
15 | }
16 | };
17 |
18 | // Apply the js-model plugin
19 | ChocoUtils.modelPlugin(<%= @plugin_name %>Plugin);
20 |
21 |
22 | // Sammy plugin
23 | // It allows you to add helper methods to your controllers and your views.
24 |
25 | (function($) {
26 |
27 | Sammy = Sammy || {};
28 |
29 | Sammy.<%= @plugin_name %> = function() {
30 |
31 | this.helper('<%= @plugin_name.underscore %>', function() {
32 | alert('hello world [sammy plugin]');
33 | });
34 |
35 | };
36 |
37 | })(jQuery);
38 |
39 | // Add this line to your application_controller.js to use this plugin :
40 | // this.use(Sammy.<%= @plugin_name %>);
--------------------------------------------------------------------------------
/lib/choco/generators/templates/models/base.js:
--------------------------------------------------------------------------------
1 | var <%= @model_name %> = Model("<%= @model %>", {
2 | persistence: Model.RestPersistence("/<%= @route_path %>"),
3 |
4 | // Class methods
5 | }, {
6 | // Instance methods
7 | });
--------------------------------------------------------------------------------
/lib/choco/generators/templates/views/edit.template:
--------------------------------------------------------------------------------
1 |
7 | <% end -%>
8 |
9 |
10 | Back to index
--------------------------------------------------------------------------------
/spec/choco_spec.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2 |
3 | describe "Choco" do
4 | end
5 |
--------------------------------------------------------------------------------
/spec/dependency_manager_spec.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2 |
3 | describe Choco::DependencyManager do
4 |
5 | def in_file(file, dependency, after = '')
6 | i = 0
7 | after_after = false
8 |
9 | File.new(file, "r").each do |line|
10 | after_after = true if line.include?(after)
11 | if after != ''
12 | i += 1 if after_after && line.include?(dependency)
13 | else
14 | i += 1 if line.include?(dependency)
15 | end
16 | end
17 | i
18 | end
19 |
20 | before(:each) do
21 | @project_path = 'spec/tmp/test_project'
22 | Choco::AppGenerator.start @project_path
23 | FileUtils.cd(@project_path)
24 | end
25 |
26 | after(:each) do
27 | FileUtils.cd('../../..')
28 | FileUtils.rm_rf(@project_path)
29 | end
30 |
31 | describe "adding dependencies" do
32 |
33 | describe "when it's a controller" do
34 |
35 | it "should add an entry in the Jimfile (controllers section)" do
36 | in_file('Jimfile', 'app/controllers/posts_controller').should == 0
37 | Choco::DependencyManager.add_dependency('app/controllers/posts_controller.js')
38 | in_file('Jimfile', 'app/controllers/posts_controller', "// Controllers # Don't remove this line!").should == 1
39 | end
40 |
41 | it "should configure it in the application controller" do
42 | in_file('app/controllers/application_controller.js', 'ArticlesController(this);').should == 0
43 | Choco::DependencyManager.add_dependency('app/controllers/articles_controller.js')
44 | in_file('app/controllers/application_controller.js',
45 | 'ArticlesController(this);',
46 | "/* Configure your controllers here ### Don't remove this line! */").should == 1
47 | end
48 |
49 | end
50 |
51 | describe "when it's a model" do
52 |
53 | it "should add an entry in the Jimfile (models section)" do
54 | in_file('Jimfile', 'app/models/post').should == 0
55 | Choco::DependencyManager.add_dependency('app/models/post.js')
56 | in_file('Jimfile', 'app/models/post', "// Models # Don't remove this line!").should == 1
57 | end
58 |
59 | end
60 |
61 | describe "when it's a helper" do
62 |
63 | it "should add an entry in the Jimfile (helpers section)" do
64 | in_file('Jimfile', 'app/helpers/test').should == 0
65 | Choco::DependencyManager.add_dependency('app/helpers/test.js')
66 | in_file('Jimfile', 'app/helpers/test', "// Helpers # Don't remove this line!").should == 1
67 | end
68 |
69 | end
70 |
71 | describe "when it's a fixture" do
72 |
73 | it "should add an entry in the Jimfile (models section)" do
74 | in_file('Jimfile', 'fixtures/posts').should == 0
75 | Choco::DependencyManager.add_dependency('fixtures/posts.js')
76 | in_file('Jimfile', 'fixtures/posts', "// Fixtures # Don't remove this line!").should == 1
77 | end
78 |
79 | end
80 |
81 | describe "when it's a lib" do
82 |
83 | it "should add an entry in the Jimfile (libs section)" do
84 | in_file('Jimfile', 'lib/my_lib').should == 0
85 | Choco::DependencyManager.add_dependency('lib/my_lib.js')
86 | in_file('Jimfile', 'lib/my_lib', "// Libs # Don't remove this line!").should == 1
87 |
88 | in_file('Jimfile', 'another/file').should == 0
89 | Choco::DependencyManager.add_dependency('another/file.js')
90 | in_file('Jimfile', 'another/file', "// Libs # Don't remove this line!").should == 1
91 | end
92 |
93 | end
94 |
95 | end
96 |
97 | describe "removing dependencies" do
98 |
99 | it "should remove the dependency from the jimfile" do
100 | Choco::DependencyManager.add_dependency('app/models/post.js')
101 | in_file('Jimfile', 'app/models/post').should == 1
102 | Choco::DependencyManager.remove_dependency('app/models/post.js')
103 | in_file('Jimfile', 'app/models/post').should == 0
104 | end
105 |
106 | describe "when it's a controller" do
107 | it "should remove the configuration from the application controller" do
108 | Choco::DependencyManager.add_dependency('app/controllers/articles_controller.js')
109 | in_file('app/controllers/application_controller.js', 'ArticlesController(this);').should == 1
110 | Choco::DependencyManager.remove_dependency('app/controllers/articles_controller.js')
111 | in_file('app/controllers/application_controller.js', 'ArticlesController(this);').should == 0
112 | end
113 | end
114 |
115 | describe "when it's a model" do
116 | it "should not change empty the application controller" do
117 | Choco::DependencyManager.remove_dependency('app/models/article.js')
118 | in_file('app/controllers/application_controller.js', 'var app = $.sammy(function() {').should == 1
119 | end
120 | end
121 |
122 | end
123 | end
--------------------------------------------------------------------------------
/spec/generators_spec.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2 |
3 | describe "Generators" do
4 |
5 | describe Choco::AppGenerator do
6 |
7 | before(:all) do
8 | @project_path = 'spec/tmp/test_project'
9 | Choco::AppGenerator.start @project_path
10 | end
11 |
12 | after(:all) do
13 | FileUtils.rm_rf @project_path
14 | end
15 |
16 | it "should generate the project folder" do
17 | File.exist?(@project_path).should be_true
18 | end
19 |
20 | it "should generate the app folder" do
21 | File.exist?(@project_path + '/app').should be_true
22 | File.exist?(@project_path + '/app/controllers').should be_true
23 | File.exist?(@project_path + '/app/helpers').should be_true
24 | File.exist?(@project_path + '/app/models').should be_true
25 | File.exist?(@project_path + '/app/views').should be_true
26 | File.exist?(@project_path + '/app/controllers/application_controller.js').should be_true
27 | File.exist?(@project_path + '/app/views/main/index.template').should be_true
28 | File.exist?(@project_path + '/app/helpers/application_helper.js').should be_true
29 | end
30 |
31 | it "should generate the lib folder" do
32 | File.exist?(@project_path + '/lib').should be_true
33 | File.exist?(@project_path + '/lib/application.js').should be_true
34 | end
35 |
36 | it "should generate the images folder" do
37 | File.exist?(@project_path + '/images').should be_true
38 | end
39 |
40 | it "should generate the stylesheets folder" do
41 | File.exist?(@project_path + '/stylesheets').should be_true
42 | File.exist?(@project_path + '/stylesheets/application.css').should be_true
43 | end
44 |
45 | it "should generate the fixtures folder" do
46 | File.exist?(@project_path + '/fixtures').should be_true
47 | end
48 |
49 | it "should generate the spec folder" do
50 | File.exist?(@project_path + '/spec').should be_true
51 | end
52 |
53 | it "should generate the script folder" do
54 | File.exist?(@project_path + '/script').should be_true
55 | File.exist?(@project_path + '/script/choco').should be_true
56 | end
57 |
58 | it "should generate the main files" do
59 | File.exist?(@project_path + '/Jimfile').should be_true
60 | File.exist?(@project_path + '/Rakefile').should be_true
61 | File.exist?(@project_path + '/README.rdoc').should be_true
62 | File.exist?(@project_path + '/index.html').should be_true
63 | end
64 |
65 | describe "templates" do
66 |
67 | describe "index.html" do
68 |
69 | before(:all) do
70 | @file = get_file_as_string(@project_path + '/index.html')
71 | end
72 |
73 | it "should include the bundled.js file" do
74 | @file.include?('').should be_true
75 | end
76 |
77 | it "should include the root div" do
78 | @file.include?('').should be_true
79 | end
80 |
81 | end
82 |
83 | end
84 | end
85 |
86 | describe "code generators" do
87 |
88 | before(:all) do
89 | @project_path = 'spec/tmp/test_project'
90 | Choco::AppGenerator.start @project_path
91 | FileUtils.cd(@project_path)
92 | end
93 |
94 | after(:all) do
95 | FileUtils.cd('..')
96 | FileUtils.rm_rf('test_project')
97 | FileUtils.cd('../..')
98 | end
99 |
100 | describe Choco::ControllerGenerator do
101 |
102 | it "should generate a controller file and a views folder" do
103 | Choco::ControllerGenerator.start 'posts'
104 | File.exist?('app/controllers/posts_controller.js').should be_true
105 | File.exist?('app/views/posts').should be_true
106 | end
107 |
108 | it "should not pluralize the controller name" do
109 | Choco::ControllerGenerator.start 'singular'
110 | File.exist?('app/controllers/singular_controller.js').should be_true
111 | end
112 |
113 | it "should underscore the name" do
114 | Choco::ControllerGenerator.start 'UnderScore'
115 | File.exist?('app/controllers/under_score_controller.js').should be_true
116 | end
117 |
118 | describe "templates" do
119 |
120 | before(:all) do
121 | Choco::ControllerGenerator.start 'UnderScore'
122 | @file = get_file_as_string('app/controllers/under_score_controller.js')
123 | end
124 |
125 | describe "the generated controller" do
126 | it "should be named correctly" do
127 | @file.include?('UnderScoreController').should be_true
128 | end
129 |
130 | it "should define an index route" do
131 | @file.include?("get('#/under_score'").should be_true
132 | end
133 | end
134 | end
135 | end
136 |
137 | describe Choco::ModelGenerator do
138 | it "should generate a model file" do
139 | Choco::ModelGenerator.start 'post'
140 | File.exist?('app/models/post.js').should be_true
141 | end
142 |
143 | it "should generate a model file with a singular name" do
144 | Choco::ModelGenerator.start 'posts'
145 | File.exist?('app/models/post.js').should be_true
146 | end
147 |
148 | describe "templates" do
149 |
150 | describe "the generated model" do
151 |
152 | before(:all) do
153 | Choco::ModelGenerator.start 'post'
154 | @file = get_file_as_string('app/models/post.js')
155 | end
156 |
157 | it "should be named correctly" do
158 | @file.include?('var Post = Model("post"').should be_true
159 | end
160 |
161 | it "model persistence URL should be correct" do
162 | @file.include?('Model.RestPersistence("/posts")').should be_true
163 | end
164 | end
165 |
166 | end
167 | end
168 |
169 | describe Choco::LayoutGenerator do
170 | it "should generate a layout file" do
171 | Choco::LayoutGenerator.start 'main'
172 | File.exist?('app/views/layouts/main.js').should be_true
173 | end
174 |
175 | describe "templates" do
176 |
177 | it "the layout should be named correctly" do
178 | Choco::LayoutGenerator.start 'main'
179 | file = get_file_as_string('app/views/layouts/main.js')
180 | file.include?('var MainLayout').should be_true
181 | end
182 |
183 | end
184 |
185 | end
186 |
187 | describe Choco::FixtureGenerator do
188 | it "should generate a fixture file" do
189 | Choco::FixtureGenerator.start 'posts'
190 | File.exist?('fixtures/posts.js').should be_true
191 | end
192 |
193 | it "should generate a fixture folder" do
194 | Choco::FixtureGenerator.start 'posts'
195 | File.exist?('fixtures/posts').should be_true
196 | File.exist?('fixtures/posts/posts.json').should be_true
197 | end
198 |
199 | describe "templates" do
200 |
201 | it "the URL should have a correct format" do
202 | Choco::FixtureGenerator.start 'post'
203 | file = get_file_as_string('fixtures/posts.js')
204 | file.include?("url: '/posts',").should be_true
205 | end
206 |
207 | end
208 |
209 | end
210 |
211 | describe Choco::PluginGenerator do
212 | it "should generate a plugin file" do
213 | Choco::PluginGenerator.start 'live'
214 | File.exist?('lib/plugin_live.js').should be_true
215 | end
216 |
217 | describe "templates" do
218 |
219 | describe "the generated plugin" do
220 |
221 | before(:all) do
222 | Choco::PluginGenerator.start 'live'
223 | @file = get_file_as_string('lib/plugin_live.js')
224 | end
225 |
226 | it "should be named correctly" do
227 | @file.include?('var LivePlugin').should be_true
228 | end
229 |
230 | it "should apply the js-model plugin" do
231 | @file.include?('ChocoUtils.modelPlugin(LivePlugin);').should be_true
232 | end
233 |
234 | it "should display the syntax to activate the sammy plugin" do
235 | @file.include?('// this.use(Sammy.Live);').should be_true
236 | end
237 |
238 | end
239 |
240 | end
241 | end
242 |
243 | describe Choco::ScaffoldGenerator do
244 | describe "with a list of fields" do
245 | it "should generate a scaffold based on the list of fields given as argument" do
246 | gen = Choco::ScaffoldGenerator.new(['post', ['author', 'title', 'content']])
247 | gen.invoke
248 |
249 | File.exist?('app/controllers/posts_controller.js').should be_true
250 | File.exist?('app/models/post.js').should be_true
251 | File.exist?('app/views/posts/index.template').should be_true
252 | File.exist?('app/views/posts/show.template').should be_true
253 | File.exist?('app/views/posts/new.template').should be_true
254 | File.exist?('app/views/posts/edit.template').should be_true
255 | end
256 | end
257 |
258 | describe "with a URL" do
259 | it "should generate a scaffold based on the fields present in the JSON response" do
260 | url = 'http://localhost:3000/posts'
261 | gen = Choco::ScaffoldGenerator.new(['post', url])
262 | json = [{"title" => "Please, contribute!","author" => "antho","content" => "What do you think about Choco?"}]
263 |
264 | gen.should_receive(:open).with(url, 'UserAgent' => 'Choco').and_return(StringIO.new)
265 | JSON.should_receive(:parse).and_return(json)
266 |
267 | gen.invoke
268 |
269 | gen.keys.should == ["author", "title", "content"]
270 | File.exist?('app/controllers/posts_controller.js').should be_true
271 | File.exist?('app/models/post.js').should be_true
272 | File.exist?('app/views/posts/index.template').should be_true
273 | File.exist?('app/views/posts/show.template').should be_true
274 | File.exist?('app/views/posts/new.template').should be_true
275 | File.exist?('app/views/posts/edit.template').should be_true
276 | end
277 | end
278 |
279 | describe "templates" do
280 |
281 | before(:each) do
282 | gen = Choco::ScaffoldGenerator.new(['post', ['author', 'title', 'content']])
283 | gen.invoke
284 | end
285 |
286 | it "the index file should have a column for each field" do
287 | file = get_file_as_string('app/views/posts/index.template')
288 | file.include?("
Author
").should be_true
289 | file.include?("
Title
").should be_true
290 | file.include?("
Content
").should be_true
291 | file.include?("
<%= post.attr('author') %>
").should be_true
292 | file.include?("
<%= post.attr('title') %>
").should be_true
293 | file.include?("
<%= post.attr('content') %>
").should be_true
294 | end
295 |
296 | it "the show file should have a label for each field" do
297 | file = get_file_as_string('app/views/posts/show.template')
298 | file.include?("").should be_true
299 | file.include?("").should be_true
300 | file.include?("").should be_true
301 | end
302 |
303 | it "the new file should have a field for each field" do
304 | file = get_file_as_string('app/views/posts/new.template')
305 | file.include?('').should be_true
306 | file.include?('').should be_true
307 | file.include?('').should be_true
308 | end
309 |
310 | it "the edit file should have a field for each field" do
311 | file = get_file_as_string('app/views/posts/edit.template')
312 | file.include?(%Q()).should be_true
313 | file.include?(%Q()).should be_true
314 | file.include?(%Q()).should be_true
315 | end
316 |
317 | end
318 | end
319 | end
320 | end
321 |
--------------------------------------------------------------------------------
/spec/spec.opts:
--------------------------------------------------------------------------------
1 | --color
2 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | $LOAD_PATH.unshift(File.dirname(__FILE__))
2 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3 | require 'rubygems'
4 | require 'choco'
5 | require 'spec'
6 | require 'spec/autorun'
7 |
8 | def get_file_as_string(filename)
9 | data = ''
10 | f = File.open(filename, "r")
11 | f.each_line { |line| data += line }
12 | data
13 | end
14 |
15 | Spec::Runner.configure do |config|
16 |
17 | end
18 |
--------------------------------------------------------------------------------