javascript 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +164 -0
- data/Rakefile +11 -0
- data/javascript.gemspec +31 -0
- data/lib/javascript.rb +326 -0
- data/lib/javascript/no_conflict.rb +5 -0
- data/lib/javascript/version.rb +3 -0
- data/test/javascript_test.rb +276 -0
- data/test/no_conflict_test.rb +23 -0
- data/test/test_helper.rb +15 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 544e1722b5fdd2b8b5e4413429f6b2dbcc712510
|
4
|
+
data.tar.gz: 3223853a5070525beec270b95deb495daeef882d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 87f978520f3e4852bae730566faac9b46685ef8874991a2ef2151827ba3d50e52d4de43910d4dbc893dea83350fecf45bbeaba7aea5fcc8284130fcf46e90d97
|
7
|
+
data.tar.gz: 3180b93400097eee3fd7d6e09d135f2c3d4e2cb39d87d48bf3298bf856dd4fddea42f1e24f5829b9e28d42dc417d2212b794c6e096634683dee2f343e9ce5756
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Godfrey Chan
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# JavaScript
|
2
|
+
|
3
|
+
As much as we love writing Ruby, when you need to *get closer to the metal*, you
|
4
|
+
have no choice but to use JavaScript. With this gem, Rubyists can finally
|
5
|
+
harness the raw power of their machines by dropping down to the metal *right
|
6
|
+
inside their Ruby applications*.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'javascript'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install javascript
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require "javascript"
|
28
|
+
|
29
|
+
puts "This is totally Ruby"
|
30
|
+
|
31
|
+
javascript {
|
32
|
+
|
33
|
+
console.log("ZOMG JavaScript");
|
34
|
+
|
35
|
+
var a = 1;
|
36
|
+
|
37
|
+
console.log(a);
|
38
|
+
|
39
|
+
a = a + 1;
|
40
|
+
|
41
|
+
console.log(a);
|
42
|
+
|
43
|
+
var b = function(x) {
|
44
|
+
console.log(x + 1);
|
45
|
+
};
|
46
|
+
|
47
|
+
b(3);
|
48
|
+
|
49
|
+
function c(x) {
|
50
|
+
console.log(x + 2);
|
51
|
+
}
|
52
|
+
|
53
|
+
c(4);
|
54
|
+
|
55
|
+
function inspectArguments() {
|
56
|
+
var args = Array.prototype.join.call(arguments, ", ");
|
57
|
+
console.log("Arguments: " + args);
|
58
|
+
}
|
59
|
+
|
60
|
+
inspectArguments("a", "b", "c");
|
61
|
+
|
62
|
+
inspectArguments(1, 2, 3, 4, 5);
|
63
|
+
|
64
|
+
}
|
65
|
+
|
66
|
+
puts "This is Ruby again"
|
67
|
+
```
|
68
|
+
|
69
|
+
Output:
|
70
|
+
|
71
|
+
```
|
72
|
+
% ruby test.rb
|
73
|
+
This is totally Ruby
|
74
|
+
ZOMG JavaScript
|
75
|
+
1
|
76
|
+
2
|
77
|
+
4
|
78
|
+
6
|
79
|
+
Arguments: a, b, c
|
80
|
+
Arguments: 1, 2, 3, 4, 5
|
81
|
+
This is Ruby again
|
82
|
+
%
|
83
|
+
```
|
84
|
+
|
85
|
+
### JavaScript + Rails = <3
|
86
|
+
|
87
|
+
Because Rails embraces callbacks, this gem is the perfectly compliment for your
|
88
|
+
Rails application. For example:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
require "javascript"
|
92
|
+
|
93
|
+
class Post < ActiveRecord::Base
|
94
|
+
before_create &javascript {
|
95
|
+
function(post) {
|
96
|
+
post.slug = post.title.parameterize();
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
Alternatively:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
require "javascript"
|
106
|
+
|
107
|
+
class Post < ActiveRecord::Base
|
108
|
+
before_create &javascript {
|
109
|
+
function() {
|
110
|
+
this.slug = this.title.parameterize();
|
111
|
+
}
|
112
|
+
}
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
### No Conflict Mode
|
117
|
+
|
118
|
+
If the `javascript` helper conflicts with an existing method, you use this gem
|
119
|
+
in the "no conflict" mode:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
require "javascript/no_conflict"
|
123
|
+
|
124
|
+
# Or add this to your Gemfile:
|
125
|
+
#
|
126
|
+
# gem "javascript", require: "javascript/no_conflict"
|
127
|
+
#
|
128
|
+
|
129
|
+
JavaScript.eval {
|
130
|
+
console.log("JavaScript here");
|
131
|
+
}
|
132
|
+
|
133
|
+
# You can also define your own helper method
|
134
|
+
|
135
|
+
module Kernel
|
136
|
+
private def metal(&block)
|
137
|
+
JavaScript.eval(&block)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
metal {
|
142
|
+
console.log("JavaScript here");
|
143
|
+
}
|
144
|
+
```
|
145
|
+
|
146
|
+
## Pros
|
147
|
+
|
148
|
+
* Gives you the illusion of programming in a *closer to the metal* syntax.
|
149
|
+
* The examples in this README actually work.
|
150
|
+
[](https://travis-ci.org/vanruby/javascript)
|
151
|
+
|
152
|
+
## Cons
|
153
|
+
|
154
|
+
* Things that aren't covered in the examples probably won't ever work.
|
155
|
+
([Check the tests](/test/javascript_test.rb))
|
156
|
+
* [Not enough jQuery](http://meta.stackexchange.com/questions/45176/when-is-use-jquery-not-a-valid-answer-to-a-javascript-question)
|
157
|
+
|
158
|
+
## Contributing
|
159
|
+
|
160
|
+
1. Fork it ( https://github.com/vanruby/javascript/fork )
|
161
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
162
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
163
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
164
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/javascript.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "javascript/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "javascript"
|
8
|
+
spec.version = JavaScript::VERSION
|
9
|
+
spec.authors = ["Godfrey Chan"]
|
10
|
+
spec.email = ["godfreykfc@gmail.com"]
|
11
|
+
spec.summary = "Seamlessly drop down to the metal with JavaScript"
|
12
|
+
spec.description = "With this gem you can finally get closer to the metal" \
|
13
|
+
"and harness the raw power of your machine by writing " \
|
14
|
+
"JavaScript code right within your Ruby applications."
|
15
|
+
spec.homepage = "https://github.com/vanruby/javascript"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^test/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.required_ruby_version = ">= 2.1.0"
|
24
|
+
|
25
|
+
spec.add_dependency "binding_of_caller", "~> 0.7.0"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
28
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
29
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
30
|
+
spec.add_development_dependency "activesupport", "~> 4.1.0"
|
31
|
+
end
|
data/lib/javascript.rb
ADDED
@@ -0,0 +1,326 @@
|
|
1
|
+
require "javascript/version"
|
2
|
+
require "binding_of_caller"
|
3
|
+
|
4
|
+
def supress_warnings
|
5
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
6
|
+
yield
|
7
|
+
ensure
|
8
|
+
$VERBOSE = verbose
|
9
|
+
end
|
10
|
+
|
11
|
+
module JavaScript
|
12
|
+
def self.eval(&block)
|
13
|
+
Scope.new.__eval__(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.current_scope
|
17
|
+
@scope
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.current_scope=(scope)
|
21
|
+
@scope = scope
|
22
|
+
end
|
23
|
+
|
24
|
+
# Make it an `Object` instead of `BasicObject` so that we can bind
|
25
|
+
# any instance methods from `Object` and call them here
|
26
|
+
class BlankObject
|
27
|
+
supress_warnings do
|
28
|
+
instance_methods(true).each { |meth| undef_method(meth) }
|
29
|
+
private_instance_methods(true).each { |meth| undef_method(meth) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module Internals
|
34
|
+
supress_warnings do
|
35
|
+
def __send__(meth, *args, &block)
|
36
|
+
__method__(:public_send).call(meth, *args, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def __method__(name)
|
42
|
+
::Object.instance_method(name).bind(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
def __binding__
|
46
|
+
__method__(:binding).call.of_caller(1)
|
47
|
+
end
|
48
|
+
|
49
|
+
def __caller__
|
50
|
+
__binding__.of_caller(2)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Object < BlankObject
|
55
|
+
include Internals
|
56
|
+
|
57
|
+
def initialize(proto = nil)
|
58
|
+
@hash = { __proto__: proto }
|
59
|
+
end
|
60
|
+
|
61
|
+
def [](key)
|
62
|
+
if @hash.key?(key)
|
63
|
+
@hash[key]
|
64
|
+
elsif __proto__
|
65
|
+
__proto__[key]
|
66
|
+
else
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def []=(key, value)
|
72
|
+
@hash[key.to_sym] = value
|
73
|
+
end
|
74
|
+
|
75
|
+
def ==(other)
|
76
|
+
__method__(:==).call(other)
|
77
|
+
end
|
78
|
+
|
79
|
+
def ===(other)
|
80
|
+
self == other
|
81
|
+
end
|
82
|
+
|
83
|
+
def !=(other)
|
84
|
+
!(self == other)
|
85
|
+
end
|
86
|
+
|
87
|
+
def __hash__
|
88
|
+
@hash
|
89
|
+
end
|
90
|
+
|
91
|
+
def __proto__
|
92
|
+
@hash[:__proto__]
|
93
|
+
end
|
94
|
+
|
95
|
+
def __defined__?(key)
|
96
|
+
@hash.key?(key) || (__proto__ && __proto__.__defined__?(key))
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
def method_missing(name, *args, &block)
|
101
|
+
if name =~ /=\z/
|
102
|
+
self[name[0...-1].to_sym] = args[0]
|
103
|
+
elsif Function === self[name]
|
104
|
+
self[name].apply(self, args)
|
105
|
+
else
|
106
|
+
self[name]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class GlobalObject < Object
|
112
|
+
def initialize
|
113
|
+
super
|
114
|
+
@hash[:console] = Console.new
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
module Syntax
|
119
|
+
private
|
120
|
+
def window
|
121
|
+
@global
|
122
|
+
end
|
123
|
+
|
124
|
+
def global
|
125
|
+
@global
|
126
|
+
end
|
127
|
+
|
128
|
+
def this
|
129
|
+
@target
|
130
|
+
end
|
131
|
+
|
132
|
+
def undefined
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
|
136
|
+
def var(*identifiers)
|
137
|
+
end
|
138
|
+
|
139
|
+
def new(identifier)
|
140
|
+
::Object.const_get(identifier.name).new(*identifier.args)
|
141
|
+
end
|
142
|
+
|
143
|
+
def function(*args, &block)
|
144
|
+
if args.length == 1 && Function === args[0]
|
145
|
+
hash = @parent ? @locals : global.__hash__
|
146
|
+
hash[args[0].name] = args[0]
|
147
|
+
else
|
148
|
+
Function.new(nil, args, block)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class Scope < BlankObject
|
154
|
+
include Internals
|
155
|
+
include Syntax
|
156
|
+
|
157
|
+
def initialize(parent = nil, target = nil, locals = {})
|
158
|
+
@parent = parent
|
159
|
+
@global = parent ? parent.__global__ : GlobalObject.new
|
160
|
+
@locals = locals
|
161
|
+
|
162
|
+
if Scope === target
|
163
|
+
@target = target.__target__
|
164
|
+
else
|
165
|
+
@target = target || global
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def __global__
|
170
|
+
@global
|
171
|
+
end
|
172
|
+
|
173
|
+
def __target__
|
174
|
+
@target
|
175
|
+
end
|
176
|
+
|
177
|
+
def __spawn__(target = nil, locals = {})
|
178
|
+
Scope.new(self, target, locals)
|
179
|
+
end
|
180
|
+
|
181
|
+
def __eval__(*args, &block)
|
182
|
+
JavaScript.current_scope = self
|
183
|
+
__method__(:instance_exec).call(*args, &block)
|
184
|
+
ensure
|
185
|
+
JavaScript.current_scope = @parent
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
def method_missing(name, *args, &block)
|
190
|
+
found = false
|
191
|
+
value = nil
|
192
|
+
defined = __caller__.local_variable_defined?(name) rescue nil
|
193
|
+
|
194
|
+
if defined
|
195
|
+
found = true
|
196
|
+
value = __caller__.local_variable_get(name)
|
197
|
+
elsif @locals.key?(name)
|
198
|
+
found = true
|
199
|
+
value = @locals[name]
|
200
|
+
elsif !@parent && @global.__defined__?(name)
|
201
|
+
found = true
|
202
|
+
value = @global[name]
|
203
|
+
end
|
204
|
+
|
205
|
+
if found && Function === value
|
206
|
+
value.apply(nil, args)
|
207
|
+
elsif found
|
208
|
+
value
|
209
|
+
elsif @parent
|
210
|
+
@parent.__send__(name, *args, &block)
|
211
|
+
elsif block.nil?
|
212
|
+
Identifier.new(name, args)
|
213
|
+
else
|
214
|
+
Function.new(name, args, block)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class Identifier < Struct.new(:name, :args); end
|
220
|
+
|
221
|
+
class Function < Struct.new(:name, :args, :body)
|
222
|
+
def initialize(*)
|
223
|
+
@scope = JavaScript.current_scope
|
224
|
+
super
|
225
|
+
end
|
226
|
+
|
227
|
+
def arity
|
228
|
+
args.length
|
229
|
+
end
|
230
|
+
|
231
|
+
def call(target = nil, *arg_values)
|
232
|
+
::Object.instance_method(:instance_exec).bind(target).call(*arg_values, &self)
|
233
|
+
end
|
234
|
+
|
235
|
+
def apply(target = nil, arg_values)
|
236
|
+
call(target, *arg_values)
|
237
|
+
end
|
238
|
+
|
239
|
+
def bind(target)
|
240
|
+
BoundFunction.new(target, name, args, body)
|
241
|
+
end
|
242
|
+
|
243
|
+
def to_proc
|
244
|
+
parent_scope = @scope
|
245
|
+
arg_names = args.map(&:name)
|
246
|
+
unwrapped = body
|
247
|
+
|
248
|
+
FunctionWrapper.new(arg_names) do |*arg_values|
|
249
|
+
locals = Hash[ arg_names.zip(arg_values) ]
|
250
|
+
locals[:arguments] = arg_values
|
251
|
+
parent_scope.__spawn__(self, locals).__eval__(*arg_values, &unwrapped)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class BoundFunction < Function
|
257
|
+
def initialize(target, name, args, body)
|
258
|
+
super(name, args, body)
|
259
|
+
@target = target
|
260
|
+
end
|
261
|
+
|
262
|
+
def call(_, *arg_values)
|
263
|
+
super(@target, *arg_values)
|
264
|
+
end
|
265
|
+
|
266
|
+
def apply(_, arg_values)
|
267
|
+
super(@target, arg_values)
|
268
|
+
end
|
269
|
+
|
270
|
+
def bind(_)
|
271
|
+
self
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
class FunctionWrapper < Proc
|
276
|
+
def initialize(args, &block)
|
277
|
+
@args = args
|
278
|
+
super(&block)
|
279
|
+
end
|
280
|
+
|
281
|
+
def arity
|
282
|
+
@args.length
|
283
|
+
end
|
284
|
+
|
285
|
+
def parameters
|
286
|
+
@args.map { |arg| [:required, arg.to_sym] }
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
class Prototype < Object
|
291
|
+
def initialize(klass)
|
292
|
+
super(nil)
|
293
|
+
@klass = klass
|
294
|
+
end
|
295
|
+
|
296
|
+
private
|
297
|
+
def method_missing(name, *args, &block)
|
298
|
+
meth = @klass.instance_method(name)
|
299
|
+
args = meth.parameters.map { |_, name| name && Identifier.new(name) }.compact
|
300
|
+
body = ->(*args) { meth.bind(this).call(*args) }
|
301
|
+
Function.new(name, args, body)
|
302
|
+
rescue NameError
|
303
|
+
super
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class Console
|
308
|
+
def log(*args)
|
309
|
+
puts(*args)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
unless defined?(JavaScript::NO_CONFLICT)
|
315
|
+
module Kernel
|
316
|
+
def javascript(&block)
|
317
|
+
JavaScript.eval(&block)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
class Class
|
322
|
+
def prototype
|
323
|
+
JavaScript::Prototype.new(self)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
$messages = []
|
4
|
+
|
5
|
+
module JavaScript
|
6
|
+
class Console
|
7
|
+
private def puts(message)
|
8
|
+
$messages << message
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class JavaScriptTest < TestCase
|
14
|
+
teardown do
|
15
|
+
$messages.clear
|
16
|
+
end
|
17
|
+
|
18
|
+
test "undefined" do
|
19
|
+
require "javascript"
|
20
|
+
assert_nil javascript { undefined }
|
21
|
+
end
|
22
|
+
|
23
|
+
test "this" do
|
24
|
+
require "javascript"
|
25
|
+
|
26
|
+
javascript do
|
27
|
+
console.log(this === window);
|
28
|
+
console.log(this === global);
|
29
|
+
end
|
30
|
+
|
31
|
+
assert_messages true, true
|
32
|
+
end
|
33
|
+
|
34
|
+
test "Local variables" do
|
35
|
+
require "javascript"
|
36
|
+
|
37
|
+
javascript {
|
38
|
+
var a = 1, b = 2;
|
39
|
+
|
40
|
+
console.log(a);
|
41
|
+
console.log(b);
|
42
|
+
|
43
|
+
a = a + 1;
|
44
|
+
b = a + b;
|
45
|
+
|
46
|
+
console.log(a);
|
47
|
+
console.log(b);
|
48
|
+
}
|
49
|
+
|
50
|
+
assert_messages 1, 2, 2, 4
|
51
|
+
end
|
52
|
+
|
53
|
+
test "Global variables" do
|
54
|
+
require "javascript"
|
55
|
+
|
56
|
+
javascript {
|
57
|
+
window.a = 1;
|
58
|
+
global.b = 2;
|
59
|
+
|
60
|
+
console.log(a);
|
61
|
+
console.log(b);
|
62
|
+
|
63
|
+
console.log(a === window.a);
|
64
|
+
console.log(a === global.a);
|
65
|
+
|
66
|
+
console.log(b === window.b);
|
67
|
+
console.log(b === global.b);
|
68
|
+
}
|
69
|
+
|
70
|
+
assert_messages 1, 2, true, true, true, true
|
71
|
+
end
|
72
|
+
|
73
|
+
test "Global object is not shared between different javascript blocks" do
|
74
|
+
require "javascript"
|
75
|
+
|
76
|
+
javascript { window.a = 1; }
|
77
|
+
assert_nil javascript { window.a; }
|
78
|
+
end
|
79
|
+
|
80
|
+
test "Functions" do
|
81
|
+
require "javascript"
|
82
|
+
|
83
|
+
javascript {
|
84
|
+
var a = function(msg) {
|
85
|
+
console.log("a: " + msg);
|
86
|
+
};
|
87
|
+
|
88
|
+
function b(msg) {
|
89
|
+
console.log("b: " + msg);
|
90
|
+
}
|
91
|
+
|
92
|
+
var c = "c";
|
93
|
+
|
94
|
+
a("hello");
|
95
|
+
b("hello");
|
96
|
+
|
97
|
+
a(c);
|
98
|
+
b(c);
|
99
|
+
}
|
100
|
+
|
101
|
+
assert_messages "a: hello", "b: hello", "a: c", "b: c"
|
102
|
+
end
|
103
|
+
|
104
|
+
test "arguments" do
|
105
|
+
require "javascript"
|
106
|
+
|
107
|
+
javascript {
|
108
|
+
function inspect() {
|
109
|
+
console.log(arguments.length);
|
110
|
+
console.log(arguments);
|
111
|
+
}
|
112
|
+
|
113
|
+
inspect("a", "b", "c");
|
114
|
+
inspect(1, 2, 3, 4, 5);
|
115
|
+
inspect();
|
116
|
+
}
|
117
|
+
|
118
|
+
assert_messages 3, ["a", "b", "c"], 5, [1, 2, 3, 4, 5], 0, []
|
119
|
+
end
|
120
|
+
|
121
|
+
test "Function#call" do
|
122
|
+
require "javascript"
|
123
|
+
|
124
|
+
javascript do
|
125
|
+
var thisCheck = function(expected) {
|
126
|
+
console.log(this === expected);
|
127
|
+
};
|
128
|
+
|
129
|
+
thisCheck(this);
|
130
|
+
thisCheck("abc");
|
131
|
+
|
132
|
+
thisCheck.call(this, this);
|
133
|
+
thisCheck.call(this, "abc");
|
134
|
+
|
135
|
+
thisCheck.call("abc", "abc");
|
136
|
+
thisCheck.call("abc", this);
|
137
|
+
|
138
|
+
var argsCheck = function() {
|
139
|
+
console.log(this == arguments);
|
140
|
+
};
|
141
|
+
|
142
|
+
argsCheck.call([1, 2, 3], 1, 2, 3);
|
143
|
+
argsCheck.call([1, 2, 3], 4, 5, 6);
|
144
|
+
argsCheck.call([1, 2, 3], [1, 2, 3]);
|
145
|
+
end
|
146
|
+
|
147
|
+
assert_messages true, false, true, false, true, false, true, false, false
|
148
|
+
end
|
149
|
+
|
150
|
+
test "Function#apply" do
|
151
|
+
require "javascript"
|
152
|
+
|
153
|
+
javascript do
|
154
|
+
var thisCheck = function(expected) {
|
155
|
+
console.log(this === expected);
|
156
|
+
};
|
157
|
+
|
158
|
+
thisCheck(this);
|
159
|
+
thisCheck("abc");
|
160
|
+
|
161
|
+
thisCheck.apply(this, [this]);
|
162
|
+
thisCheck.apply(this, ["abc"]);
|
163
|
+
|
164
|
+
thisCheck.apply("abc", ["abc"]);
|
165
|
+
thisCheck.apply("abc", [this]);
|
166
|
+
|
167
|
+
var argsCheck = function() {
|
168
|
+
console.log(this == arguments);
|
169
|
+
};
|
170
|
+
|
171
|
+
argsCheck.apply([1, 2, 3], [1, 2, 3]);
|
172
|
+
argsCheck.apply([1, 2, 3], [4, 5, 6]);
|
173
|
+
end
|
174
|
+
|
175
|
+
assert_messages true, false, true, false, true, false, true, false
|
176
|
+
end
|
177
|
+
|
178
|
+
test "Function#bind" do
|
179
|
+
require "javascript"
|
180
|
+
|
181
|
+
javascript do
|
182
|
+
var thisCheck = function(expected) {
|
183
|
+
console.log(this === expected);
|
184
|
+
};
|
185
|
+
|
186
|
+
thisCheck = thisCheck.bind("abc");
|
187
|
+
|
188
|
+
thisCheck(this);
|
189
|
+
thisCheck("abc");
|
190
|
+
|
191
|
+
thisCheck.call(this, this);
|
192
|
+
thisCheck.call(this, "abc");
|
193
|
+
thisCheck.call("abc", "abc");
|
194
|
+
|
195
|
+
var argsCheck = function() {
|
196
|
+
console.log(this == arguments);
|
197
|
+
};
|
198
|
+
|
199
|
+
argsCheck = argsCheck.bind([1, 2, 3]);
|
200
|
+
|
201
|
+
argsCheck.call("abc", 1, 2, 3);
|
202
|
+
argsCheck.apply("abc", [1, 2, 3]);
|
203
|
+
|
204
|
+
argsCheck.call("abc", 4, 5, 6);
|
205
|
+
argsCheck.apply("abc", [4, 5, 6]);
|
206
|
+
end
|
207
|
+
|
208
|
+
assert_messages false, true, false, true, true, true, true, false, false
|
209
|
+
end
|
210
|
+
|
211
|
+
test "Prototype" do
|
212
|
+
require "javascript"
|
213
|
+
|
214
|
+
javascript {
|
215
|
+
var join = Array.prototype.join;
|
216
|
+
|
217
|
+
console.log(join.call(["a", "b", "c"], "+"));
|
218
|
+
console.log(join.call([1, 2, 3, 4, 5], "-"));
|
219
|
+
}
|
220
|
+
|
221
|
+
assert_messages "a+b+c", "1-2-3-4-5"
|
222
|
+
end
|
223
|
+
|
224
|
+
test "Callback" do
|
225
|
+
require "javascript"
|
226
|
+
require "active_support/callbacks"
|
227
|
+
require "active_support/core_ext/string/inflections"
|
228
|
+
|
229
|
+
class Post < Struct.new(:title, :slug)
|
230
|
+
include ActiveSupport::Callbacks
|
231
|
+
|
232
|
+
define_callbacks :create, :destroy
|
233
|
+
|
234
|
+
set_callback :create, :before, &javascript {
|
235
|
+
function(post) {
|
236
|
+
console.log("Before");
|
237
|
+
post.slug = post.title.parameterize();
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
241
|
+
set_callback :destroy, :after, &javascript {
|
242
|
+
function() {
|
243
|
+
console.log("After");
|
244
|
+
this.slug = undefined;
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
def create
|
249
|
+
run_callbacks(:create)
|
250
|
+
end
|
251
|
+
|
252
|
+
def destroy
|
253
|
+
run_callbacks(:destroy)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
post = Post.new("Hello world!")
|
258
|
+
|
259
|
+
assert_nil post.slug
|
260
|
+
|
261
|
+
post.create
|
262
|
+
|
263
|
+
assert_equal "hello-world", post.slug
|
264
|
+
|
265
|
+
post.destroy
|
266
|
+
|
267
|
+
assert_nil post.slug
|
268
|
+
|
269
|
+
assert_messages "Before", "After"
|
270
|
+
end
|
271
|
+
|
272
|
+
private
|
273
|
+
def assert_messages(*messages)
|
274
|
+
assert_equal messages, $messages
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class NoConflictTest < TestCase
|
4
|
+
test "Global `javascript` helper is not available in no-conflict mode" do
|
5
|
+
require "javascript/no_conflict"
|
6
|
+
assert_raises(NoMethodError) { javascript { 1 } }
|
7
|
+
end
|
8
|
+
|
9
|
+
test "Global monkey-patch is not available in no-conflict mode" do
|
10
|
+
require "javascript/no_conflict"
|
11
|
+
assert_raises(NoMethodError) { JavaScript.eval { Array.prototype } }
|
12
|
+
end
|
13
|
+
|
14
|
+
test "Defining custom helper in no-conflict mode" do
|
15
|
+
require "javascript/no_conflict"
|
16
|
+
|
17
|
+
def metal(&block)
|
18
|
+
JavaScript.eval(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
assert_equal 1, metal { 1 }
|
22
|
+
end
|
23
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "minitest/autorun"
|
3
|
+
require "minitest/pride"
|
4
|
+
require "active_support"
|
5
|
+
require "active_support/testing/declarative"
|
6
|
+
require "active_support/testing/setup_and_teardown"
|
7
|
+
require "active_support/testing/isolation"
|
8
|
+
|
9
|
+
I18n.enforce_available_locales = true
|
10
|
+
|
11
|
+
class TestCase < Minitest::Test
|
12
|
+
extend ActiveSupport::Testing::Declarative
|
13
|
+
include ActiveSupport::Testing::SetupAndTeardown
|
14
|
+
include ActiveSupport::Testing::Isolation
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: javascript
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Godfrey Chan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: binding_of_caller
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.7.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.7.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activesupport
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.1.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.1.0
|
83
|
+
description: With this gem you can finally get closer to the metaland harness the
|
84
|
+
raw power of your machine by writing JavaScript code right within your Ruby applications.
|
85
|
+
email:
|
86
|
+
- godfreykfc@gmail.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".travis.yml"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- javascript.gemspec
|
98
|
+
- lib/javascript.rb
|
99
|
+
- lib/javascript/no_conflict.rb
|
100
|
+
- lib/javascript/version.rb
|
101
|
+
- test/javascript_test.rb
|
102
|
+
- test/no_conflict_test.rb
|
103
|
+
- test/test_helper.rb
|
104
|
+
homepage: https://github.com/vanruby/javascript
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata: {}
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 2.1.0
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 2.2.2
|
125
|
+
signing_key:
|
126
|
+
specification_version: 4
|
127
|
+
summary: Seamlessly drop down to the metal with JavaScript
|
128
|
+
test_files:
|
129
|
+
- test/javascript_test.rb
|
130
|
+
- test/no_conflict_test.rb
|
131
|
+
- test/test_helper.rb
|