Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Replace 'johnson' with ExecJS #1

Merged
merged 6 commits into from

2 participants

@ArthurN

In the process of trying to integrate therubyracer to support Ruby 1.9.2 per your blog comment, I ended up discovering ExecJS, which can work with any number of JS runtimes including both johnson and therubyracer. That seemed like the better solution, so here it is. As such, it ends up being up to the user of Isotope to select the runtime to work with ExecJS.

Additionally, I fixed a small bug in the spec (timezone-vs-UTC dates) and updated the Date.parse code to the latest version from this repo. The example application is also updated. I have NOT updated the Readme, however.

I've tested this with:
1.8.7 using johnson
1.8.7 using therubyracer
1.9.2 using therubyracer

on both the spec and the example app.

Cheers!

@elado
Owner

Thanks!
Didn't have the chance to look deeper into the code, but the test succeeds on 1.8.7-p334 and fails on 1.9.2. Can you check?

$ rspec test/isotope_spec.rb 
rewriting path constants for test...
/Users/Elad/Sites/temp/isotope/test/isotope_spec.rb:7: warning: already initialized constant APP_ROOT
/Users/Elad/Sites/temp/isotope/test/isotope_spec.rb:8: warning: already initialized constant DEFAULT_CONFIG_PATH
.FF

Failures:

  1) Isotope should render articles
     Failure/Error: evaluated_content = Isotope.render_partial(@template_file, :locals => { :item => @articles[0] })
     ExecJS::ProgramError:
       ReferenceError: formatDate is not defined
     # ./lib/isotope/isotope.rb:44:in `render_partial'
     # ./test/isotope_spec.rb:45:in `block (2 levels) in <top (required)>'

  2) Isotope should render an array of articles
     Failure/Error: evaluated_content = Isotope.render_partial(@template_file, :collection => @articles, :delimiter => "<hr/>")
     ExecJS::ProgramError:
       ReferenceError: formatDate is not defined
     # ./lib/isotope/isotope.rb:44:in `render_partial'
     # ./lib/isotope/isotope.rb:57:in `block in render_partial_collection'
     # ./lib/isotope/isotope.rb:52:in `each'
     # ./lib/isotope/isotope.rb:52:in `render_partial_collection'
     # ./lib/isotope/isotope.rb:35:in `render_partial'
     # ./test/isotope_spec.rb:65:in `block (2 levels) in <top (required)>'

Finished in 0.1307 seconds
3 examples, 2 failures
@ArthurN

What runtime are you using on 1.9.2, johnson or therubyracer?

Note that I intentionally did not require any runtime gem in isotope's Gemfile. My thinking was that the application will include whatever runtime it prefers in the Gemfile in addition to isotope itself. However, for simplicity's sake, we could just include 'therubyracer' in the isotope Gemfile. I'd have to double-check, but I think that ExecJS will prefer therubyracer over johnson if both are available on the system.

@ArthurN

The reason I ask, of course, is because it seems to be working for me:

[507][arthur.Inception: isotope]$ rvm current
ruby-1.9.2-p180
[508][arthur.Inception: isotope]$ gem list | grep johnson
[509][arthur.Inception: isotope]$ gem list | grep rubyracer
therubyracer (0.9.3beta1, 0.9.2)
[510][arthur.Inception: isotope]$ rspec test/isotope_spec.rb 
rewriting path constants for test...
/Users/arthur/Projects/isotope/test/isotope_spec.rb:7: warning: already initialized constant APP_ROOT
/Users/arthur/Projects/isotope/test/isotope_spec.rb:8: warning: already initialized constant DEFAULT_CONFIG_PATH
...

Finished in 0.06601 seconds
3 examples, 0 failures
@elado
Owner

OK, the problem was that I didn't have therubyracer gem on my 1.9. Please add it to the Gemfile and iI'll merge.
Thanks!

@ArthurN

Will take care of that, as well as a small bug I discovered, tomorrow. Thanks!

@ArthurN

Updated

@elado
Owner

Thanks

Two fixes needed:

  1. Add a semicolon after included scripts
  2. Concatenate strings with << instead of +=

    initial_script = included_scripts_source ? included_scripts_source + ";" : ""
    initial_script << IO.read(isotope_file_path)

I'll merge after that. Thanks so much for contributing!

@ArthurN

Good call. Updated.

@elado elado merged commit 4243fdd into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
6 Gemfile
@@ -1,5 +1,7 @@
-source :rubygemss
+source :rubygems
source :gemcutter
source "http://gems.github.com"
-gem "johnson"
+gem 'json'
+gem 'therubyracer'
+gem 'execjs'
View
13 Gemfile.lock
@@ -1,11 +1,20 @@
GEM
remote: http://rubygems.org/
+ remote: http://rubygems.org/
remote: http://gems.github.com/
specs:
- johnson (1.2.0)
+ execjs (1.2.0)
+ multi_json (~> 1.0)
+ json (1.5.3)
+ libv8 (3.3.10.2)
+ multi_json (1.0.3)
+ therubyracer (0.9.2)
+ libv8 (~> 3.3.10)
PLATFORMS
ruby
DEPENDENCIES
- johnson
+ execjs
+ json
+ therubyracer
View
7 examples/rails3-example/Gemfile
@@ -2,7 +2,12 @@ source 'http://rubygems.org'
gem 'rails', '>=3.0.0'
+# Pick your JS runtime (see https://github.com/sstephenson/execjs)
+gem 'therubyracer'
+#gem 'johnson'
+
# gem 'isotope'
gem 'json'
-gem 'johnson'
+gem 'execjs'
+
gem 'sqlite3-ruby', :require => 'sqlite3'
View
104 examples/rails3-example/Gemfile.lock
@@ -2,76 +2,82 @@ GEM
remote: http://rubygems.org/
specs:
abstract (1.0.0)
- actionmailer (3.0.0)
- actionpack (= 3.0.0)
- mail (~> 2.2.5)
- actionpack (3.0.0)
- activemodel (= 3.0.0)
- activesupport (= 3.0.0)
+ actionmailer (3.0.7)
+ actionpack (= 3.0.7)
+ mail (~> 2.2.15)
+ actionpack (3.0.7)
+ activemodel (= 3.0.7)
+ activesupport (= 3.0.7)
builder (~> 2.1.2)
erubis (~> 2.6.6)
- i18n (~> 0.4.1)
+ i18n (~> 0.5.0)
rack (~> 1.2.1)
- rack-mount (~> 0.6.12)
- rack-test (~> 0.5.4)
+ rack-mount (~> 0.6.14)
+ rack-test (~> 0.5.7)
tzinfo (~> 0.3.23)
- activemodel (3.0.0)
- activesupport (= 3.0.0)
+ activemodel (3.0.7)
+ activesupport (= 3.0.7)
builder (~> 2.1.2)
- i18n (~> 0.4.1)
- activerecord (3.0.0)
- activemodel (= 3.0.0)
- activesupport (= 3.0.0)
- arel (~> 1.0.0)
+ i18n (~> 0.5.0)
+ activerecord (3.0.7)
+ activemodel (= 3.0.7)
+ activesupport (= 3.0.7)
+ arel (~> 2.0.2)
tzinfo (~> 0.3.23)
- activeresource (3.0.0)
- activemodel (= 3.0.0)
- activesupport (= 3.0.0)
- activesupport (3.0.0)
- arel (1.0.1)
- activesupport (~> 3.0.0)
+ activeresource (3.0.7)
+ activemodel (= 3.0.7)
+ activesupport (= 3.0.7)
+ activesupport (3.0.7)
+ arel (2.0.10)
builder (2.1.2)
erubis (2.6.6)
abstract (>= 1.0.0)
- i18n (0.4.1)
- johnson (1.2.0)
- json (1.4.6)
- mail (2.2.7)
+ execjs (1.2.0)
+ multi_json (~> 1.0)
+ i18n (0.5.0)
+ json (1.5.3)
+ libv8 (3.3.10.2)
+ mail (2.2.19)
activesupport (>= 2.3.6)
- mime-types
- treetop (>= 1.4.5)
+ i18n (>= 0.4.0)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
mime-types (1.16)
+ multi_json (1.0.3)
polyglot (0.3.1)
- rack (1.2.1)
- rack-mount (0.6.13)
+ rack (1.2.3)
+ rack-mount (0.6.14)
rack (>= 1.0.0)
- rack-test (0.5.6)
+ rack-test (0.5.7)
rack (>= 1.0)
- rails (3.0.0)
- actionmailer (= 3.0.0)
- actionpack (= 3.0.0)
- activerecord (= 3.0.0)
- activeresource (= 3.0.0)
- activesupport (= 3.0.0)
- bundler (~> 1.0.0)
- railties (= 3.0.0)
- railties (3.0.0)
- actionpack (= 3.0.0)
- activesupport (= 3.0.0)
- rake (>= 0.8.4)
- thor (~> 0.14.0)
- rake (0.8.7)
+ rails (3.0.7)
+ actionmailer (= 3.0.7)
+ actionpack (= 3.0.7)
+ activerecord (= 3.0.7)
+ activeresource (= 3.0.7)
+ activesupport (= 3.0.7)
+ bundler (~> 1.0)
+ railties (= 3.0.7)
+ railties (3.0.7)
+ actionpack (= 3.0.7)
+ activesupport (= 3.0.7)
+ rake (>= 0.8.7)
+ thor (~> 0.14.4)
+ rake (0.9.0)
sqlite3-ruby (1.3.1)
- thor (0.14.3)
- treetop (1.4.8)
+ therubyracer (0.9.2)
+ libv8 (~> 3.3.10)
+ thor (0.14.6)
+ treetop (1.4.9)
polyglot (>= 0.3.1)
- tzinfo (0.3.23)
+ tzinfo (0.3.29)
PLATFORMS
ruby
DEPENDENCIES
- johnson
+ execjs
json
rails (>= 3.0.0)
sqlite3-ruby
+ therubyracer
View
61 examples/rails3-example/public/javascripts/isotope_functions.js
@@ -10,7 +10,7 @@ function getOrdinalSuffix(n) {
function formatDate(dateISO8601) {
var date = new Date(Date.parse(dateISO8601));
- return getMonthName(date.getMonth())+" "+date.getDate()+getOrdinalSuffix(date.getDate())+", "+date.getFullYear();
+ return getMonthName(date.getUTCMonth())+" "+date.getUTCDate()+getOrdinalSuffix(date.getUTCDate())+", "+date.getUTCFullYear();
}
String.prototype.parenthesize = function () {
@@ -18,29 +18,44 @@ String.prototype.parenthesize = function () {
};
/**
- * Date.parse with progressive enhancement for ISO-8601, version 2
+ * Date.parse with progressive enhancement for ISO-8601, version 5
* © 2010 Colin Snover <http://zetafleet.com>
* Released under MIT license.
*/
// http://zetafleet.com/blog/javascript-dateparse-for-iso-8601
-(function () {
- var origParse = Date.parse;
- Date.parse = function (date) {
- var timestamp = origParse(date), minutesOffset = 0, struct;
- if (isNaN(timestamp) && (struct = /^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(date))) {
- if (struct[8] !== 'Z') {
- minutesOffset = +struct[10] * 60 + (+struct[11]);
-
- if (struct[9] === '+') {
- minutesOffset = 0 - minutesOffset;
- }
- }
-
- if (!struct[7]) struct[7] = "0000";
-
- timestamp = new Date(+struct[1], +struct[2] - 1, +struct[3], +struct[4], +struct[5] + minutesOffset, +struct[6], +struct[7].substr(0, 3)).getTime();
- }
-
- return timestamp;
- };
-}());
+(function (Date, undefined) {
+ var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
+ Date.parse = function (date) {
+ var timestamp, struct, minutesOffset = 0;
+
+ // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
+ // before falling back to any implementation-specific date parsing, so that’s what we do, even if native
+ // implementations could be faster
+ // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm
+ if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
+ // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC
+ for (var i = 0, k; (k = numericKeys[i]); ++i) {
+ struct[k] = +struct[k] || 0;
+ }
+
+ // allow undefined days and months
+ struct[2] = (+struct[2] || 1) - 1;
+ struct[3] = +struct[3] || 1;
+
+ if (struct[8] !== 'Z' && struct[9] !== undefined) {
+ minutesOffset = struct[10] * 60 + struct[11];
+
+ if (struct[9] === '+') {
+ minutesOffset = 0 - minutesOffset;
+ }
+ }
+
+ timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]);
+ }
+ else {
+ timestamp = origParse ? origParse(date) : NaN;
+ }
+
+ return timestamp;
+ };
+}(Date));
View
15 lib/isotope/isotope.rb
@@ -1,5 +1,5 @@
require 'rubygems'
-require 'johnson'
+require 'execjs'
require 'json'
require 'yaml'
require 'erb'
@@ -39,14 +39,13 @@ def self.render_partial(view_file, options = {})
view_file_content = template_file_content(view_file)
- script = "
- #{included_scripts_source}
- Johnson.runtime.load('#{isotope_file_path}');
- Isotope(#{view_file_content.to_json}, #{options[:locals].to_json});
- "
+ initial_script = included_scripts_source ? included_scripts_source + ";" : ""
+ initial_script << IO.read(isotope_file_path)
+
+ context = ExecJS.compile(initial_script)
+ script = "Isotope(#{view_file_content.to_json}, #{options[:locals].to_json})"
+ output = context.eval(script)
- output = Johnson.evaluate(script)
-
output
end
View
61 test/isotope_functions.js
@@ -10,7 +10,7 @@ function getOrdinalSuffix(n) {
function formatDate(dateISO8601) {
var date = new Date(Date.parse(dateISO8601));
- return getMonthName(date.getMonth())+" "+date.getDate()+getOrdinalSuffix(date.getDate())+", "+date.getFullYear();
+ return getMonthName(date.getUTCMonth())+" "+date.getUTCDate()+getOrdinalSuffix(date.getUTCDate())+", "+date.getUTCFullYear();
}
String.prototype.parenthesize = function () {
@@ -18,29 +18,44 @@ String.prototype.parenthesize = function () {
};
/**
- * Date.parse with progressive enhancement for ISO-8601, version 2
+ * Date.parse with progressive enhancement for ISO-8601, version 5
* © 2010 Colin Snover <http://zetafleet.com>
* Released under MIT license.
*/
// http://zetafleet.com/blog/javascript-dateparse-for-iso-8601
-(function () {
- var origParse = Date.parse;
- Date.parse = function (date) {
- var timestamp = origParse(date), minutesOffset = 0, struct;
- if (isNaN(timestamp) && (struct = /^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(date))) {
- if (struct[8] !== 'Z') {
- minutesOffset = +struct[10] * 60 + (+struct[11]);
-
- if (struct[9] === '+') {
- minutesOffset = 0 - minutesOffset;
- }
- }
-
- if (!struct[7]) struct[7] = "0000";
-
- timestamp = new Date(+struct[1], +struct[2] - 1, +struct[3], +struct[4], +struct[5] + minutesOffset, +struct[6], +struct[7].substr(0, 3)).getTime();
- }
-
- return timestamp;
- };
-}());
+(function (Date, undefined) {
+ var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
+ Date.parse = function (date) {
+ var timestamp, struct, minutesOffset = 0;
+
+ // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
+ // before falling back to any implementation-specific date parsing, so that’s what we do, even if native
+ // implementations could be faster
+ // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm
+ if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
+ // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC
+ for (var i = 0, k; (k = numericKeys[i]); ++i) {
+ struct[k] = +struct[k] || 0;
+ }
+
+ // allow undefined days and months
+ struct[2] = (+struct[2] || 1) - 1;
+ struct[3] = +struct[3] || 1;
+
+ if (struct[8] !== 'Z' && struct[9] !== undefined) {
+ minutesOffset = struct[10] * 60 + struct[11];
+
+ if (struct[9] === '+') {
+ minutesOffset = 0 - minutesOffset;
+ }
+ }
+
+ timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]);
+ }
+ else {
+ timestamp = origParse ? origParse(date) : NaN;
+ }
+
+ return timestamp;
+ };
+}(Date));
Something went wrong with that request. Please try again.