Created
October 6, 2010 23:40
-
-
Save TylerRick/614311 to your computer and use it in GitHub Desktop.
Proc#to_json, JavascriptCode#to_json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This allows you to represents a JavaScript function with a proc. When converted to JSON, it will | |
# automatically wrap the method body with "function(){" and "}" and list as many arguments as you | |
# had listed in your proc, automatically giving them the names a, b, c, etc. | |
# | |
# This is convenient when you want to create a Ruby hash representating options to be passed to | |
# a JavaScript method, which you plan to call to_json on when you actually output the method call | |
# to the web page. If you tried to represent your JavaScript function with a string value in the | |
# hash, then when you called to_json on the hash, it would in turn call String#to_json, which | |
# returns an escaped copy of the string surrounded by quotes. | |
# | |
# For example, this: | |
# { :onComplete => 'function() { alert("Done loading") }' }.to_json | |
# | |
# would become: | |
# {"onComplete":"function() { alert(\"Done loading\") }"} | |
# | |
# and your callback would probably not do anything (unless they eval'ed the string first) because | |
# the API probably expects you to pass in an actual JavaScript *function*, not a string. | |
# | |
# What we need is a way to represent literal JavaScript *code* rather than a literal JavaScript string. | |
# | |
# By defining Proc#to_json, we can do just that: use a Proc to represents in Ruby a JavaScript function. | |
# | |
# Now this: | |
# { :onComplete => proc{'alert("Done loading")'} }.to_json | |
# | |
# becomes this: | |
# {"onComplete":function() { alert("Done loading") }} | |
# | |
# If you want to represent a JavaScript function that takes arguments, you just list your arguments | |
# in the Ruby proc, like so: | |
# { :onComplete => proc{|a, b| 'alert("Finished loading page "+a+" in "+b+" seconds")'} }.to_json | |
# | |
# Which becomes this: | |
# {"onComplete":function(a, b) { alert("Finished loading page "+a+" in "+b+" seconds") }} | |
# | |
# The only stipulation is that you write your method body such that it expects the arguments to be | |
# named a, b, c, etc. (There's no way that I know of to inspect a Ruby Proc object and find out the | |
# original names given to its arguments when it was created. But there is a way to ask it how *many* | |
# arguments it takes, and that is what I used.) | |
# | |
# Author: Tyler Rick | |
class Proc | |
def to_json(options = nil) #:nodoc: | |
arg_list = (1..arity).map {|i| ('a'.ord + i - 1).chr}.join(', ') | |
"function(#{arg_list}) { #{call} }" | |
end | |
def javascript_call | |
JavascriptCode("(#{to_json})()") | |
end | |
end | |
# Now suppose you need to represent not a JavaScript *function*, but some snippet of arbitrary | |
# JavaScript code that should get executed *immediately* (assuming you output to a web page). | |
# This code could be a calculation, evaluating a variable, or anything, really. | |
# | |
# In this case, using a Proc does not work. Instead, you can use a "JavascriptCode" object to | |
# represent this JavaScript code in Ruby. | |
# | |
# Example: | |
# JavascriptCode('some_config_option * 100').to_json | |
# Becomes this: | |
# some_config_option * 100 | |
# | |
# Alternatively, you can still use the Proc, but instead of passing it into your hash directly, | |
# you can call its 'javascript_call' method, which as the name implies, creates a JavascriptCode | |
# that calls the anonymous JavaScript function by appending '()' to the end. | |
# | |
# Example: | |
# proc{'return some_config_option * 100'}.javascript_call | |
# Becomes this JavascriptCode: | |
# (function() { return some_config_option * 100 })() | |
# | |
# Authors: | |
# * Danny Beardsley (http://forthecommunity.blogspot.com/2010/06/function-definitions-in-json-un-quoted.html) | |
# * Tyler Rick | |
class JavascriptCode < String | |
def to_json(options = nil) | |
self | |
end | |
end | |
module Kernel | |
# A convenience factory method | |
def JavascriptCode(str) | |
JavascriptCode.new(str) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
Didn't work for me, then I realized I was including
active_support/*
which includes it's own to_json. Adding this to your JavascriptCode class did the trick: