edifice 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in edifice.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,14 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ edifice (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ edifice!
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 iCyte
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.
data/README ADDED
@@ -0,0 +1,46 @@
1
+ Edifice
2
+ =======
3
+
4
+ Edifice is a Javascript framework released as a rails plugin.
5
+
6
+
7
+ framework.js + associated helpers
8
+ ---------------------------------
9
+
10
+ The idea here is to communicate which view is rendering to the javascript so that we can call the correct javascript files in an automagical way.
11
+
12
+ All you need to do is add
13
+ <%= edifice_meta_tags %>
14
+ to your layout, in the head.
15
+
16
+ Then if you render an action, such as users/show, in the layout application, these functions[if they exist] will be fired on these js objects in the following order:
17
+
18
+ document.ready:
19
+ - usersShow.onReady
20
+ - layoutsApplication.onReady
21
+ - [widgets are loaded]
22
+ - usersShow.onWidgetReady
23
+ - layoutsApplication.onWidgetReady
24
+
25
+ document.load:
26
+ - usersShow.onLoad
27
+ - layoutsApplication.onLoad
28
+
29
+ suppose we then subsequently load users/edit via ajax, in the layout xhr. Then the following events will fire:
30
+ - usersEdit.onAjaxComplete
31
+ - layoutsXhr.onAjaxComplete
32
+ - usersShow.onAjaxComplete
33
+ - layoutsApplication.onAjaxComplete
34
+ - [widgets are loaded]
35
+ - usersEdit.onWidgetReady
36
+ - layoutsXhr.onWidgetReady
37
+ - usersShow.onWidgetReady
38
+ - layoutsApplication.onWidgetReady
39
+
40
+ widgets
41
+ -------
42
+
43
+ forms
44
+ -----
45
+
46
+ Copyright (c) 2010 iCyte, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/edifice.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "edifice/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "edifice"
7
+ s.version = Edifice::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Tom Coleman", "Zoltan Olah", "Joe Dollard"]
10
+ s.email = ["tom@thesnail.org", "zol@me.com", "jdollard@gmail.com"]
11
+ s.homepage = "http://github.com/tmeasday/edifice"
12
+ s.summary = %q{Ediface is a Javascript framework released as a rails plugin.}
13
+ s.description = %q{The idea here is to communicate which view is rendering to the javascript so that we can call the correct javascript files in an automagical way.}
14
+
15
+ s.rubyforge_project = "edifice"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
data/init.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'edifice'
2
+
3
+ config.to_prepare do
4
+ Edifice.install_js_files
5
+ end
6
+
7
+ ActionController::Base.send :include, Edifice::Controller
8
+ # ActionMailer::Base.send :include, Edifice::Controller
9
+ ActionView::Base.send :include, EdificeHelper
@@ -0,0 +1,3 @@
1
+ module Edifice
2
+ VERSION = "0.0.1"
3
+ end
data/lib/edifice.rb ADDED
@@ -0,0 +1,54 @@
1
+ module Edifice
2
+ def self.install_js_files
3
+ install_dir = ::Rails.application.paths.public.javascripts.first
4
+ edifice_js_dir = File.join(File.dirname(__FILE__), 'public', 'javascripts', 'edifice')
5
+
6
+ FileUtils.cp_r edifice_js_dir, install_dir
7
+ end
8
+
9
+ module Controller
10
+ def self.included(controller)
11
+ controller.helper_method(:view_path, :view_path_normalized,
12
+ :view_name, :view_name_normalized, :layout_name)
13
+
14
+ unless (controller == ActionMailer::Base)
15
+ controller.after_filter(:write_edifice_headers)
16
+ controller.alias_method_chain(:_render_template, :edifice)
17
+ end
18
+ end
19
+
20
+ def _render_template_with_edifice(options)
21
+ @view_path = options[:prefix]
22
+ @view_name = options[:template]
23
+ @layout = File.split(options[:layout]).last
24
+
25
+ _render_template_without_edifice(options)
26
+ end
27
+
28
+ def write_edifice_headers
29
+ response.headers['x-edifice-view_path'] = view_path_normalized
30
+ response.headers['x-edifice-view_name'] = view_name_normalized
31
+ response.headers['x-edifice-layout'] = layout_name
32
+ end
33
+
34
+ def view_path
35
+ (@view_path || 'no_controller').gsub('/', '_')
36
+ end
37
+
38
+ def view_path_normalized
39
+ view_path.camelcase(:lower)
40
+ end
41
+
42
+ def view_name
43
+ @view_name || 'no_view'
44
+ end
45
+
46
+ def view_name_normalized
47
+ view_name.camelcase(:lower)
48
+ end
49
+
50
+ def layout_name
51
+ @layout || 'no_layout'
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,14 @@
1
+ module EdificeHelper
2
+ # put this in your layout somewhere
3
+ def edifice_meta_tags
4
+ %(<meta name='edifice-view_path' content='#{view_path_normalized}'/>
5
+ <meta name='edifice-view_name' content='#{view_name_normalized}'/>
6
+ <meta name='edifice-layout' content='#{layout_name}'/>).html_safe
7
+ end
8
+
9
+ # the default classes that get added to the body element when a view renders
10
+ # the c_ in front of view_path is for historical reasons
11
+ def edifice_body_classes
12
+ %(c_#{view_path} v_#{view_name} l_#{layout_name}").html_safe
13
+ end
14
+ end
@@ -0,0 +1,187 @@
1
+ /*
2
+ Turn a standard form into an 'ajax' form.
3
+
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..
7
+
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
+ });
40
+
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
+ });
50
+ }
51
+
52
+
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
+ };
59
+
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;
82
+
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;
115
+ });
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);
159
+ return false;
160
+ }
161
+ }
162
+
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
+ }
181
+ } else {
182
+ this.focus();
183
+ }
184
+ });
185
+ };
186
+ }(jQuery));
187
+
@@ -0,0 +1,205 @@
1
+ /**
2
+ * @fileOverview a proto-framework for javascript-rails integration using jQuery
3
+ * @author Tom Coleman
4
+ * @author Zoltan Olah
5
+ * @author Joe Dollard
6
+ */
7
+
8
+ jQuery.noConflict();
9
+
10
+ /**
11
+ @name $.fn
12
+ @namespace
13
+ @description jQuery Plugins
14
+ */
15
+ (function($){
16
+ /**
17
+ * Runs an 'event method' on a view object and a layout object defined by meta tags
18
+ * we specially set in every layout.
19
+ *
20
+ * @param {String} methodName The method to call on the view object corresponding to event that's happening.
21
+ */
22
+ function page_level_hookup(methodName) {
23
+ var view_path = $('meta[name=edifice-view_path]').attr('content');
24
+ var view_name = $('meta[name=edifice-view_name]').attr('content');
25
+ var layout = $('meta[name=edifice-layout]').attr('content');
26
+
27
+ hookup(methodName, view_path, view_name, layout);
28
+ };
29
+
30
+ /**
31
+ * Runs an 'event method' on a view object and a layout object defined by the headers
32
+ * we specially set on ajax requests.
33
+ *
34
+ * @param {String} methodName The method to call on the view object corresponding to event that's happening.
35
+ * @param {XMLHttpRequest} request The returning ajax request.
36
+ */
37
+ function ajax_hookup(methodName, request) {
38
+ var view_path = request.getResponseHeader('x-edifice-view_path');
39
+ var view_name = request.getResponseHeader('x-edifice-view_name');
40
+ var layout = request.getResponseHeader('x-edifice-layout');
41
+
42
+ hookup(methodName, view_path, view_name, layout);
43
+ }
44
+
45
+ /**
46
+ * Runs an 'event method' on a view object and a layout object.
47
+ * @example hookup('onLoad', 'annos', 'list', 'application);
48
+ * Will call annosList.onLoad() and layoutsApplication.onLoad() if they exist.
49
+ *
50
+ * @param {String} methodName The method to call on the view object corresponding to event that's happening.
51
+ * @param {String} view_path The camelcased path to the view, often the same as the controller name.
52
+ * @param {String} view_name The name of the view being rendered.
53
+ * @param {String} layout The layout being used. If there is no layout this is 'no_layout'
54
+ */
55
+ function hookup(methodName, view_path, view_name, layout) {
56
+ //capitalize the first character in a string
57
+ function capitalize_first_chr(str) {
58
+ if ((typeof(str) == 'undefined') || (str.length == 0)) {
59
+ return "";
60
+ }
61
+
62
+ return str.charAt(0).toUpperCase().concat( str.substr(1) )
63
+ }
64
+
65
+ hookup_once(view_path + capitalize_first_chr(view_name), methodName); // hookup the view
66
+ hookup_once('layouts' + capitalize_first_chr(layout), methodName);
67
+ };
68
+
69
+ /**
70
+ * Runs an 'event method' on a view object if it exists.
71
+ *
72
+ * @param {String} objectName The name of the view object, e.g annosList.
73
+ * @param {String} methodName The method to call on the view object corresponding to event that's happening.
74
+ */
75
+ function hookup_once(objectName, methodName) {
76
+ if (typeof window[objectName] != 'undefined') { // check for undefined in js
77
+ if (methodName in window[objectName]) {
78
+ eval("window['" + objectName + "']." + methodName + "();");
79
+ }
80
+ }
81
+ };
82
+
83
+ //when the dom is ready
84
+ $(document).ready(function() {
85
+ page_level_hookup('onReady');
86
+ $.attach_widgets();
87
+ page_level_hookup('onWidgetsReady');
88
+ $(document).trigger('widgetsReady');
89
+ });
90
+
91
+ //when the page is fully loaded (all frames, images, etc)
92
+ $(window).load(function() {
93
+ page_level_hookup('onLoad');
94
+ });
95
+
96
+ //after every ajax request
97
+ $(window).bind('ajaxComplete', function(event, request) {
98
+ ajax_hookup('onAjaxComplete', request);
99
+ page_level_hookup('onAjaxComplete');
100
+ $.attach_widgets();
101
+ ajax_hookup('onWidgetsReady', request);
102
+ page_level_hookup('onWidgetsReady');
103
+ $(document).trigger('widgetsReady');
104
+ });
105
+
106
+
107
+ // *********** EDIFACE WIDGET CODE *********** //
108
+
109
+ /**
110
+ @name $.edifice_widgets
111
+ @namespace
112
+ @description Our widgets live here.
113
+ */
114
+ $.edifice_widgets = {};
115
+
116
+ /**
117
+ * Runs attach_widget() on any widget found in the html which isn't already attached.
118
+ */
119
+ $.attach_widgets = function() {
120
+ $('[data-widget]:not([data-widget-attached])').attach_widget();
121
+ };
122
+
123
+ /**
124
+ * Call $.WIDGET_NAME on the matched elements where WIDGET_NAME is set in the
125
+ * data-widget attribute.
126
+ *
127
+ * @param {Object} extra_options Use these options in addition to those specified
128
+ * in the html as data-widget-OPTION_NAME=VALUE
129
+ *
130
+ * @throws {Exception} If a widget has already been attached.
131
+ * @throws {Exception} If the type of widget doesn't exist.
132
+ */
133
+ $.fn.attach_widget = function(extra_options) {
134
+ return this.each(function() {
135
+ var $e = $(this), fn_name = $e.attr('data-widget');
136
+
137
+ // error checking
138
+ if ($e.attr('data-widget-attached')) {
139
+ throw('attach_widget called on already attached widget.');
140
+ }
141
+ if (!(fn_name in $.edifice_widgets)) {
142
+ throw("edifice widget '" + fn_name + "' is not defined.");
143
+ }
144
+
145
+ // attach extra options to the widget
146
+ if (typeof(extra_options) != 'undefined') {
147
+ $.each(extra_options, function(name, def) {
148
+ $e.data('widget-' + name, def);
149
+ });
150
+ }
151
+
152
+ // load the widget up
153
+ $.edifice_widgets[fn_name].call($e);
154
+ $e.attr('data-widget-attached', true);
155
+ });
156
+ };
157
+
158
+ /**
159
+ * Make a widget out of an element which doesn't already have data-widget set
160
+ * in the html.
161
+ *
162
+ * @param {String} Type Type of widget, e.g 'ajax_form'
163
+ * @param {Object} Options for widget.
164
+ */
165
+ $.fn.create_widget = function(type, options) {
166
+ return $(this).attr('data-widget', type).attach_widget(options);
167
+ };
168
+
169
+ /**
170
+ * @constant
171
+ */
172
+ $.edifice_widgets.REQUIRED = '*** VALUE REQUIRED ***';
173
+
174
+ /**
175
+ * Read the set of options attached to a widget via data-widget-OPTION_NAME
176
+ * in the html.
177
+ *
178
+ * @param {Object} defaults Specifies the names and default values of
179
+ * applicable options. Set default value to $.edifice_widgets.REQUIRED to indicate
180
+ * a mandatory value.
181
+ *
182
+ * @returns {Object} The options calculated.
183
+ *
184
+ * @throws {Exception} If a required option is not found.
185
+ */
186
+ $.fn.read_options = function(defaults) {
187
+ var that = this;
188
+ var options = {};
189
+ $.each(defaults, function(name, def) {
190
+ var val = that.data('widget-' + name) || that.attr('data-widget-' + name);
191
+
192
+ if (val) {
193
+ options[name] = val;
194
+ } else {
195
+ if (def === $.edifice_widgets.REQUIRED) {
196
+ throw("Widget argument required: " + name);
197
+ }
198
+
199
+ options[name] = def;
200
+ }
201
+ });
202
+
203
+ return options;
204
+ }
205
+ }(jQuery));
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: edifice
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Tom Coleman
14
+ - Zoltan Olah
15
+ - Joe Dollard
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-02-21 00:00:00 +11:00
21
+ default_executable:
22
+ dependencies: []
23
+
24
+ description: The idea here is to communicate which view is rendering to the javascript so that we can call the correct javascript files in an automagical way.
25
+ email:
26
+ - tom@thesnail.org
27
+ - zol@me.com
28
+ - jdollard@gmail.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files: []
34
+
35
+ files:
36
+ - .gitignore
37
+ - Gemfile
38
+ - Gemfile.lock
39
+ - MIT-LICENSE
40
+ - README
41
+ - Rakefile
42
+ - edifice.gemspec
43
+ - init.rb
44
+ - lib/edifice.rb
45
+ - lib/edifice/version.rb
46
+ - lib/edifice_helper.rb
47
+ - lib/public/javascripts/edifice/ajax_form.js
48
+ - lib/public/javascripts/edifice/framework.js
49
+ has_rdoc: true
50
+ homepage: http://github.com/tmeasday/edifice
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project: edifice
79
+ rubygems_version: 1.5.2
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Ediface is a Javascript framework released as a rails plugin.
83
+ test_files: []
84
+