edifice 0.0.5 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/.DS_Store +0 -0
  2. data/lib/edifice/form_model.rb +28 -0
  3. data/lib/edifice/helper.rb +16 -0
  4. data/lib/edifice/railtie.rb +10 -0
  5. data/lib/edifice/responder.rb +13 -0
  6. data/lib/edifice/version.rb +1 -1
  7. data/lib/edifice.rb +12 -2
  8. data/lib/public/javascripts/edifice/ajax_form.js +114 -174
  9. data/lib/public/javascripts/edifice/form.js +105 -0
  10. data/lib/tasks/edifice.rake +6 -0
  11. data/test/rails3/.gitignore +4 -0
  12. data/test/rails3/Gemfile +33 -0
  13. data/test/rails3/Gemfile.lock +75 -0
  14. data/test/rails3/README +256 -0
  15. data/test/rails3/Rakefile +7 -0
  16. data/test/rails3/app/controllers/application_controller.rb +3 -0
  17. data/test/rails3/app/controllers/posts_controller.rb +15 -0
  18. data/test/rails3/app/helpers/application_helper.rb +2 -0
  19. data/test/rails3/app/models/post.rb +10 -0
  20. data/test/rails3/app/views/layouts/application.html.erb +14 -0
  21. data/test/rails3/app/views/posts/new.html.erb +17 -0
  22. data/test/rails3/config/application.rb +50 -0
  23. data/test/rails3/config/boot.rb +6 -0
  24. data/test/rails3/config/database.yml +22 -0
  25. data/test/rails3/config/environment.rb +5 -0
  26. data/test/rails3/config/environments/development.rb +26 -0
  27. data/test/rails3/config/environments/production.rb +49 -0
  28. data/test/rails3/config/environments/test.rb +35 -0
  29. data/test/rails3/config/initializers/backtrace_silencers.rb +7 -0
  30. data/test/rails3/config/initializers/inflections.rb +10 -0
  31. data/test/rails3/config/initializers/mime_types.rb +5 -0
  32. data/test/rails3/config/initializers/secret_token.rb +7 -0
  33. data/test/rails3/config/initializers/session_store.rb +8 -0
  34. data/test/rails3/config/locales/en.yml +5 -0
  35. data/test/rails3/config/routes.rb +4 -0
  36. data/test/rails3/config.ru +4 -0
  37. data/test/rails3/db/seeds.rb +7 -0
  38. data/test/rails3/doc/README_FOR_APP +2 -0
  39. data/test/rails3/lib/tasks/.gitkeep +0 -0
  40. data/test/rails3/public/404.html +26 -0
  41. data/test/rails3/public/422.html +26 -0
  42. data/test/rails3/public/500.html +26 -0
  43. data/test/rails3/public/favicon.ico +0 -0
  44. data/test/rails3/public/images/rails.png +0 -0
  45. data/test/rails3/public/javascripts/.gitkeep +0 -0
  46. data/test/rails3/public/javascripts/application.js +0 -0
  47. data/test/rails3/public/javascripts/jquery-1.5.1.js +8316 -0
  48. data/test/rails3/public/robots.txt +5 -0
  49. data/test/rails3/public/stylesheets/.gitkeep +0 -0
  50. data/test/rails3/public/stylesheets/form.css +18 -0
  51. data/test/rails3/script/rails +6 -0
  52. data/test/rails3/vendor/plugins/.gitkeep +0 -0
  53. metadata +96 -7
  54. data/lib/edifice_helper.rb +0 -14
data/.DS_Store ADDED
Binary file
@@ -0,0 +1,28 @@
1
+ # kind of the evolution of the FormStruct
2
+
3
+ module Edifice
4
+ class FormModel
5
+ include ActiveModel::Validations
6
+ include ActiveModel::Conversion
7
+ extend ActiveModel::Naming
8
+
9
+ def initialize(attributes = {})
10
+ attributes.each { |n, v| send("#{n}=", v) if respond_to?("#{n}=") }
11
+ end
12
+
13
+ # default implementation, override as necessary
14
+ def save
15
+ valid?
16
+ end
17
+
18
+ def self.create(attributes = {})
19
+ form = new(attributes)
20
+ form.save
21
+ form
22
+ end
23
+
24
+ def persisted?
25
+ false
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ module Edifice
2
+ module Helper
3
+ # put this in your layout somewhere
4
+ def edifice_meta_tags
5
+ %(<meta name='edifice-view_path' content='#{view_path_normalized}'/>
6
+ <meta name='edifice-view_name' content='#{view_name_normalized}'/>
7
+ <meta name='edifice-layout' content='#{layout_name}'/>).html_safe
8
+ end
9
+
10
+ # the default classes that get added to the body element when a view renders
11
+ # the c_ in front of view_path is for historical reasons
12
+ def edifice_body_classes
13
+ %(c_#{view_path} v_#{view_name} l_#{layout_name}").html_safe
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ require 'edifice'
2
+ require 'rails'
3
+
4
+ module Edifice
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load "tasks/edifice.rake"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ # Basically a standard responder, but if
2
+ module Edifice
3
+ class Responder < ActionController::Responder
4
+ protected
5
+ def to_html
6
+ if controller.request.xhr? && !get? and has_errors? && default_action
7
+ render :action => default_action, :status => :unprocessable_entity, :layout => nil
8
+ else
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module Edifice
2
- VERSION = "0.0.5"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/edifice.rb CHANGED
@@ -1,6 +1,10 @@
1
- require 'edifice_helper'
1
+ require 'edifice/helper'
2
+ require 'edifice/form_model'
3
+ require 'edifice/responder'
2
4
 
3
5
  module Edifice
6
+ require 'edifice/railtie' if defined?(Rails)
7
+
4
8
  def self.install_js_files
5
9
  install_dir = ::Rails.application.paths.public.javascripts.first
6
10
  edifice_js_dir = File.join(File.dirname(__FILE__), 'public', 'javascripts', 'edifice')
@@ -17,6 +21,12 @@ module Edifice
17
21
  controller.after_filter(:write_edifice_headers)
18
22
  controller.alias_method_chain(:_render_template, :edifice)
19
23
  end
24
+
25
+ controller.class_eval do
26
+ def self.responder
27
+ Edifice::Responder
28
+ end
29
+ end
20
30
  end
21
31
 
22
32
  def _render_template_with_edifice(options)
@@ -57,4 +67,4 @@ end
57
67
 
58
68
  ActionController::Base.send :include, Edifice::Controller
59
69
  # ActionMailer::Base.send :include, Edifice::Controller
60
- ActionView::Base.send :include, EdificeHelper
70
+ ActionView::Base.send :include, Edifice::Helper
@@ -1,187 +1,127 @@
1
- /*
2
- Turn a standard form into an 'ajax' form.
1
+ (function($) {
2
+ var defaults = {
3
+ status_element: this, // element to set to .submitting/.success/.error as we submit
4
+ // a hash of input selector -> validation functions/names
5
+ validators: {},
6
+ // type of data to pass around (and thus what's seen by e.g. success)
7
+ dataType: 'html'
8
+ };
9
+
10
+ // EVENTS that fire during the course of the life of the submission:
11
+ // submit, invalid, success | error (+ user_error | server_error), complete
12
+ //
13
+ // -> success,errors + complete are all passed the data you would expect from
14
+ // jQuery.ajax
15
+
16
+ $.edifice_widgets.ajax_form = function() { return this.each(ajax_form); }
17
+
18
+ function ajax_form() {
19
+ var $form = $(this).edifice_form();
20
+ $form.settings = $form.read_options(defaults);
21
+ $.extend($form, methods);
3
22
 
4
- -- Relies on the action that the form points to to return a 422 with a new,
5
- 'errored' form if there is a (server-side) validation problem.
6
- Otherwise calls the various callbacks..
23
+ $form.initialize();
24
+ }
25
+ var methods = {
26
+ initialize: function() {
27
+ this.prepare_validators();
28
+ this.prepare_submit();
29
+ },
30
+
31
+ prepare_validators: function() {
32
+ var $form = this;
7
33
 
8
- Extra arguments:
9
- - status_sel: the selector of an element to set the classes 'submitting/success/error'
10
- on depending on the state of the form. Defaults to the form itself.
11
- - validators: a hash of input selectors to validation functions (or names)
12
- for client-side validation.
13
- */
14
-
15
- (function($){
16
- $.edifice_widgets.ajax_form = function() {
17
- return this.each(function(){
18
- var settings = $(this).read_options({
19
- status_sel: this, // element to set to .submitting/.success/.error as we submit
20
- //default callbacks
21
- error: function(x, t, e, form){
22
- if (x.status >= 400 && x.status < 500) { // a CLIENT ERROR
23
- //validation failed replace form with new one
24
- var $new_form = $(x.responseText);
25
- $(form).replaceWith($new_form);
26
- // -- not sure this is the best way to pass extra settings through, but it seems to work.
27
- $new_form.create_widget('ajax_form', settings);
28
- } else if (x.status >= 500 && x.status < 600) { // a SERVER ERROR
29
- // replace the body proxy with the result (i.e replace the entire page)
30
- $('#body_proxy').before($(x.responseText)).remove();
31
- } else {
32
- alert('Form failed. Please try again.');
33
- }
34
- },
35
- success: function(d, s, form){},
36
- complete: function(x, t, form){},
37
- submit: function(e){}, // return false to cancel submit
38
- validators: {}
39
- });
34
+ // setup validators from settings
35
+ for (var selector in $form.settings.validators) {
36
+ $form.set_validator($(selector), $form.settings.validators[selector]);
37
+ }
38
+
39
+ // setup validators from html
40
+ $form.fields().filter('[data-widget-validator]').each(function() {
41
+ $form.set_validator($(this), $(this).attr('data-widget-validator'));
42
+ });
43
+
44
+ // listen to validator
45
+ this.fields().live('change.ajax_form focusout.ajax_form', function() {
46
+ $form.validate($(this));
47
+ });
48
+ },
49
+
50
+ prepare_submit: function() {
51
+ var $form = this;
52
+ this.submit(function(event) {
53
+ event.preventDefault();
40
54
 
41
- // prepare the validators that are references
42
- for (var selector in settings.validators) {
43
- var validator = settings.validators[selector];
44
- if (typeof(validator) === 'string') {
45
- validator = settings.validators[selector] = $.edifice_widgets.ajax_form.validators[validator];
46
- }
47
- $(selector).bind('change.ajax_form', {validator: validator}, function(event) {
48
- validate($(this), event.data.validator);
49
- });
55
+ // do pre-submit validations
56
+ if (!$form.valid()) {
57
+ $form.trigger('invalid');
58
+ $form.error_fields().eq(0).focus(); // focus the first error
59
+ return false; // we are done.
50
60
  }
51
61
 
62
+ $form.submits().attr('disabled', true); // disable submit buttons
52
63
 
53
- function set_status_class(name) {
54
- $.each(['form_submitting', 'form_success', 'form_error'], function(i, old_name) {
55
- $(settings.status_sel).removeClass(old_name);
56
- });
57
- $(settings.status_sel).addClass(name);
58
- };
64
+ // TODO - set status class
59
65
 
60
- $(this).bind("submit.ajax_form", function(ev){
61
- var form = this;
62
-
63
- ev.preventDefault();
64
-
65
- // do client-side validations
66
- var valid = true, $first_error;
67
- for (var selector in settings.validators) {
68
- if (!validate($(selector), settings.validators[selector])) {
69
- if (valid) { valid = false; $first_error = $(selector); }
70
- }
71
- }
72
- if (!valid) { $first_error.focus(); return false; }
73
-
74
- // fire a custom event allowing anyone to cancel the submission
75
- var event = $.Event('submitting.ajax_form');
76
- event.cancel = false;
77
- event.submitEvent = ev;
78
- $(form).trigger(event);
79
-
80
- if (event.cancel)
81
- return false;
66
+ // send up the form and process the results
67
+ $.ajax({
68
+ url: $form.attr('action'), type: $form.attr('method'),
69
+ dataType: $form.settings.dataType,
70
+ data: $.param($form.serializeArray()),
71
+ cache: false,
72
+ error: function (x, t, e) { $form.error(x, t, e); },
73
+ success: function (data, status) {
74
+ $form.trigger('success', data, status);
75
+ },
76
+ complete: function (request, text_status) {
77
+ $form.trigger('complete', request, text_status);
82
78
 
83
- // also run the user defined submit function
84
- if (settings.submit(ev) === false) return false;
85
-
86
- // disable the first submit button on the form
87
- $(form).find('input[type=submit]:first').attr('disabled', true);
88
-
89
- // set the status
90
- set_status_class('form_submitting');
91
-
92
- // send up the form and process the results
93
- $.ajax({
94
- cache: false,
95
- data: $.param($(form).serializeArray()),
96
- type: form.method,
97
- url: form.action,
98
- error: function (x, t, e) {
99
- settings.error(x, t, e, form);
100
- set_status_class('form_error');
101
- },
102
- success: function (d, s) {
103
- settings.success(d, s, form);
104
- set_status_class('form_success');
105
- },
106
- complete: function (x, t) {
107
- // enable the first submit button on the form
108
- $(form).find('input[type=submit]:first').attr('disabled', false);
109
-
110
- settings.complete(x, t, form);
111
- }
112
- });
113
-
114
- return false;
79
+ $form.submits().removeAttr('disabled');
80
+ }
115
81
  });
116
- });
117
- };
118
-
119
- // call this on a div that represents a form element.
120
- // sets the right classes and enables disables actual form elements
121
- $.fn.form_element_state = function(command) {
122
- switch (command) {
123
- case 'disabled':
124
- this.addClass('disabled')
125
- .find('input, select').attr('disabled', true);
126
- break;
127
- case 'enabled':
128
- this.removeClass('disabled')
129
- .find('input, select').removeAttr('disabled');
130
- break;
131
- }
132
- return this;
133
- };
134
-
135
- function clearError(id) {
136
- // run over the input and the label pointing to it
137
- $('.fieldWithErrors').find('> #' + id + ', > label[for=' + id + ']').unwrap();
138
- $('label[for=' + id + ']').next('.formError').remove();
139
- };
140
-
141
- function addError(id, error) {
142
- // right now this is causing focus issues and we don't need it, so I won't waste time
143
- // fixing it.... but it could be used for different form layouts...
144
- // $('#' + id + ', label[for=' + id + ']').wrap('<div class="fieldWithErrors"></div>');
145
- $('label[for=' + id + ']').after('<div class="formError">' + error + '</div>');
146
- };
147
-
148
- // calls a validator, and takes care of setting the errors string
149
- function validate($input, validator) {
150
- var id = $input.attr('id');
151
- // clear existing validations
152
- clearError(id);
153
-
154
- var error = validator($input);
155
- if (error === true) {
156
- return true;
157
- } else {
158
- addError(id, error);
82
+
159
83
  return false;
160
- }
161
- }
84
+ });
85
+ },
162
86
 
163
- // validators expect a form element and return true or an error message
164
- $.edifice_widgets.ajax_form.validators = {
165
- not_empty: function($input) {
166
- return $input.val() ? true : 'must not be empty';
167
- }
168
- };
169
-
170
- // standardize .focus() for input tags. IE doesn't place the focus at the
171
- // end of the input box, this fixes it
172
- $.fn.inputFocus = function() {
173
- return this.each(function(){
174
- if ($.browser.msie) {
175
- if (this.createTextRange) {
176
- var FieldRange = this.createTextRange();
177
- FieldRange.moveStart('character', this.value.length);
178
- FieldRange.collapse();
179
- FieldRange.select();
180
- }
87
+ error: function(request, text_status, error) {
88
+ this.trigger('error', request, status, error);
89
+
90
+ // handle the different possible errors that we can see
91
+ if (request.status >= 400 && request.status < 500) {
92
+ // CLIENT ERROR -- server-side validation failed.
93
+ this.trigger('client_error', request, status, error);
94
+
95
+ // if data is html, we replace this content of the form with the content
96
+ // of the form that we've just received back
97
+ if (this.settings.dataType === 'html') {
98
+ // wrap in a div incase there are a bunch of floating elements, pull the form out
99
+ var $new_form = $('<div>').append(request.responseText).find('#' + this.attr('id'));
100
+
101
+ this.html($new_form.html());
102
+ this.prepare_validators();
103
+
104
+ } else if (this.settings.dataType === 'json') {
105
+ // we will be receiving an error object back, we can pass it straight into form.js
106
+ this.set_errors($.parseJSON(request.responseText));
181
107
  } else {
182
- this.focus();
108
+ throw "Don't know how to handle dataType " + this.settings.dataType;
183
109
  }
184
- });
185
- };
186
- }(jQuery));
187
-
110
+ } else if (x.status >= 500 && x.status < 600) {
111
+ // a SERVER ERROR -- something unrecoverable happened on the server
112
+ this.trigger('server_error', request, status, error);
113
+
114
+ // we aren't going to do anything here.
115
+ // FIXME: we should probably have a way to set this behaviour at the application level.
116
+ // for instance, you probably just want to redirect to somewhere, or show a dialog,
117
+ // or popup something or.....?
118
+ } else {
119
+ // some other kind of error. Revisit
120
+ alert('Form failed. Please try again.');
121
+ }
122
+
123
+
124
+ },
125
+ }
126
+
127
+ }(jQuery));
@@ -0,0 +1,105 @@
1
+ (function($) {
2
+ $.edifice = $.edifice || {};
3
+
4
+ // add methods to a form element so it can be easily manipulated
5
+ //
6
+ // add client side validation
7
+ // understands:
8
+ // - rails form structures
9
+ // - rails form errors in JSON
10
+ // - etc
11
+ $.fn.edifice_form = function() {
12
+ $.extend(this, methods);
13
+ return this;
14
+ };
15
+
16
+ // VALIDATORS:
17
+ // validators expect a form element and return true or an error message
18
+ $.fn.edifice_form.validators = {
19
+ not_empty: function($input) {
20
+ return $input.val() ? true : 'must not be empty';
21
+ }
22
+ };
23
+
24
+
25
+ // in these 'this' is the $form
26
+ var methods = {
27
+ fields: function() {
28
+ return this.find('input, textarea, select');
29
+ },
30
+
31
+ error_fields: function() {
32
+ var $form = this;
33
+ return this.fields().filter(function() {
34
+ return $form.has_error($(this));
35
+ });
36
+ },
37
+
38
+ submits: function() {
39
+ return this.find('input[type=submit], button[type=submit]');
40
+ },
41
+
42
+ valid: function() {
43
+ var $form = this, valid = true;
44
+
45
+ this.fields().each(function() {
46
+ if (!$form.validate($(this))) { valid = false; }
47
+ });
48
+
49
+ return valid;
50
+ },
51
+
52
+ // 'prepare' a validator --> validator returns true or an error string
53
+ set_validator: function($field, validator) {
54
+ if (typeof validator === 'string') {
55
+ validator = $.fn.edifice_form.validators[validator] || validator;
56
+ if (typeof validator !== 'function') { throw "Validator not defined: '" + validator + "'"; }
57
+ };
58
+ $field.data('validator', validator);
59
+ },
60
+
61
+ // validate a single field
62
+ validate: function($field) {
63
+ var validator;
64
+ if (validator = $field.data('validator')) {
65
+ var error = validator($field), valid = error === true;
66
+ this.clear_error($field);
67
+ if (!valid) {
68
+ this.add_error($field, error);
69
+ }
70
+
71
+ return valid;
72
+ } else {
73
+ return true;
74
+ }
75
+ },
76
+
77
+ has_error: function($field) {
78
+ return $field.parent('.field_with_errors').length > 0;
79
+ },
80
+
81
+ clear_error: function($field) {
82
+ var id = $field.attr('id');
83
+ if (this.has_error($field)) { $field.unwrap() }
84
+
85
+ this.find('.field_with_errors label[for=' + id + ']')
86
+ .unwrap()
87
+ .next('.formError').remove();
88
+ },
89
+
90
+ add_error: function($field, error) {
91
+ var id = $field.attr('id');
92
+ $field.wrap('<div class="field_with_errors">');
93
+ this.find('label[for=' + id + ']')
94
+ .wrap('<div class="field_with_errors">')
95
+ .after('<div class="formError">' + error + '</div>');
96
+ },
97
+
98
+ set_errors: function(errors) {
99
+ for (var name in errors) {
100
+ this.add_error(this.fields().filter('[name*=' + name + ']'), errors[name][0]);
101
+ }
102
+ }
103
+ };
104
+
105
+ }(jQuery));
@@ -0,0 +1,6 @@
1
+ namespace :edifice do
2
+ desc "Installs the edifice JS files into public/javascripts/edifice"
3
+ task :install do
4
+ Edifice.install_js_files
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ .bundle
2
+ db/*.sqlite3
3
+ log/*.log
4
+ tmp/
@@ -0,0 +1,33 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rails', '3.0.7'
4
+
5
+ # Bundle edge Rails instead:
6
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
+
8
+ gem 'sqlite3'
9
+
10
+ gem 'dynamic_form'
11
+
12
+ # Use unicorn as the web server
13
+ # gem 'unicorn'
14
+
15
+ # Deploy with Capistrano
16
+ # gem 'capistrano'
17
+
18
+ # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
19
+ # gem 'ruby-debug'
20
+ # gem 'ruby-debug19', :require => 'ruby-debug'
21
+
22
+ # Bundle the extra gems:
23
+ # gem 'bj'
24
+ # gem 'nokogiri'
25
+ # gem 'sqlite3-ruby', :require => 'sqlite3'
26
+ # gem 'aws-s3', :require => 'aws/s3'
27
+
28
+ # Bundle gems for the local environment. Make sure to
29
+ # put test-only gems in this group so their generators
30
+ # and rake tasks are available in development mode:
31
+ # group :development, :test do
32
+ # gem 'webrat'
33
+ # end
@@ -0,0 +1,75 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.7)
6
+ actionpack (= 3.0.7)
7
+ mail (~> 2.2.15)
8
+ actionpack (3.0.7)
9
+ activemodel (= 3.0.7)
10
+ activesupport (= 3.0.7)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.5.0)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.14)
16
+ rack-test (~> 0.5.7)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.7)
19
+ activesupport (= 3.0.7)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.5.0)
22
+ activerecord (3.0.7)
23
+ activemodel (= 3.0.7)
24
+ activesupport (= 3.0.7)
25
+ arel (~> 2.0.2)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.7)
28
+ activemodel (= 3.0.7)
29
+ activesupport (= 3.0.7)
30
+ activesupport (3.0.7)
31
+ arel (2.0.10)
32
+ builder (2.1.2)
33
+ dynamic_form (1.1.4)
34
+ erubis (2.6.6)
35
+ abstract (>= 1.0.0)
36
+ i18n (0.5.0)
37
+ mail (2.2.19)
38
+ activesupport (>= 2.3.6)
39
+ i18n (>= 0.4.0)
40
+ mime-types (~> 1.16)
41
+ treetop (~> 1.4.8)
42
+ mime-types (1.16)
43
+ polyglot (0.3.1)
44
+ rack (1.2.3)
45
+ rack-mount (0.6.14)
46
+ rack (>= 1.0.0)
47
+ rack-test (0.5.7)
48
+ rack (>= 1.0)
49
+ rails (3.0.7)
50
+ actionmailer (= 3.0.7)
51
+ actionpack (= 3.0.7)
52
+ activerecord (= 3.0.7)
53
+ activeresource (= 3.0.7)
54
+ activesupport (= 3.0.7)
55
+ bundler (~> 1.0)
56
+ railties (= 3.0.7)
57
+ railties (3.0.7)
58
+ actionpack (= 3.0.7)
59
+ activesupport (= 3.0.7)
60
+ rake (>= 0.8.7)
61
+ thor (~> 0.14.4)
62
+ rake (0.9.2)
63
+ sqlite3 (1.3.3)
64
+ thor (0.14.6)
65
+ treetop (1.4.9)
66
+ polyglot (>= 0.3.1)
67
+ tzinfo (0.3.27)
68
+
69
+ PLATFORMS
70
+ ruby
71
+
72
+ DEPENDENCIES
73
+ dynamic_form
74
+ rails (= 3.0.7)
75
+ sqlite3