opal-actionpack 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b6402fa68e9baa7931c57ca82bb15c5555200ba8
4
+ data.tar.gz: 7394860f43ee4dcb9f4d8ff71f6776bd8be8c842
5
+ SHA512:
6
+ metadata.gz: b34dbefd90dda22abe217bd966b1af968c84f6f4f96e75aa5d2e5a56e704c20fdf1a1e237eceeff9398bd2aaf4a358287d980c735bc87d48923f7a05fa54f194
7
+ data.tar.gz: ec6b3b88b7e6c48aca0b48a01707103dc66617780ce3ceb35f57d9d97465d19d63262ce3ceb1f03407e94dae4db36991996b75b40e0e4950963b5a3fff3a3d5e
@@ -0,0 +1,5 @@
1
+ # VIM
2
+ .backups
3
+ **/.backups
4
+ *.swp
5
+
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'opal', :github => 'opal/opal'
6
+ gem 'opal-rspec', '0.3.0.beta2'
7
+
8
+ gem 'rspec' # for testing in MRI
9
+
@@ -0,0 +1,51 @@
1
+ GIT
2
+ remote: git://github.com/opal/opal.git
3
+ revision: 139b534a8e14719f1406318d432b305ba76db4b1
4
+ specs:
5
+ opal (0.6.0)
6
+ source_map
7
+ sprockets
8
+
9
+ PATH
10
+ remote: .
11
+ specs:
12
+ opal-actionpack (0.0.1)
13
+ opal (>= 0.5.0, < 1.0.0)
14
+
15
+ GEM
16
+ remote: https://rubygems.org/
17
+ specs:
18
+ diff-lcs (1.2.5)
19
+ hike (1.2.3)
20
+ json (1.8.1)
21
+ multi_json (1.8.4)
22
+ opal-rspec (0.3.0.beta2)
23
+ opal (>= 0.6.0, < 1.0.0)
24
+ rack (1.5.2)
25
+ rake (10.1.0)
26
+ rspec (2.14.1)
27
+ rspec-core (~> 2.14.0)
28
+ rspec-expectations (~> 2.14.0)
29
+ rspec-mocks (~> 2.14.0)
30
+ rspec-core (2.14.7)
31
+ rspec-expectations (2.14.4)
32
+ diff-lcs (>= 1.1.3, < 2.0)
33
+ rspec-mocks (2.14.4)
34
+ source_map (3.0.1)
35
+ json
36
+ sprockets (2.10.1)
37
+ hike (~> 1.2)
38
+ multi_json (~> 1.0)
39
+ rack (~> 1.0)
40
+ tilt (~> 1.1, != 1.3.0)
41
+ tilt (1.4.1)
42
+
43
+ PLATFORMS
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ opal!
48
+ opal-actionpack!
49
+ opal-rspec (= 0.3.0.beta2)
50
+ rake
51
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) <year> <copyright holders>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Elia Schito
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.
@@ -0,0 +1,46 @@
1
+ # Opal: ActiveRecord
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ gem 'opal-actionpack'
8
+
9
+ And then execute:
10
+
11
+ $ bundle
12
+
13
+ Or install it yourself as:
14
+
15
+ $ gem install opal-actionpack
16
+
17
+
18
+ ## Usage
19
+
20
+ Inside your `application.js.rb`:
21
+
22
+ ```ruby
23
+ require 'action_pack' # to require the whole action pack lib
24
+ ```
25
+
26
+ ## Testing
27
+
28
+ There are two ways to run tests. You can run them inside of MRI
29
+ for ease of testing and better debuggability or you can run them
30
+ using Opal (as this is how it will actually be used).
31
+
32
+ * To run in Opal do - rake
33
+ * To run in MRI do - rspec spec
34
+
35
+
36
+ ## Contributing
37
+
38
+ 1. Fork it
39
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
40
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
41
+ 4. Push to the branch (`git push origin my-new-feature`)
42
+ 5. Create new Pull Request
43
+
44
+ ## License
45
+
46
+ opal-activerecord is Copyright © 2014 Steve Tuckner. It is free software, and may be redistributed under the terms specified in the LICENSE file (an MIT License).
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ require 'opal/rspec/rake_task'
5
+ Opal::RSpec::RakeTask.new(:default)
6
+
7
+ require 'bundler/gem_tasks'
@@ -0,0 +1 @@
1
+ require 'opal/actionpack'
@@ -0,0 +1,5 @@
1
+ require 'opal'
2
+ require 'opal/actionpack/version'
3
+
4
+ # Just register our opal code path with opal build tools
5
+ Opal.append_path File.expand_path('../../../opal', __FILE__)
@@ -0,0 +1,5 @@
1
+ module Opal
2
+ module Actionpack
3
+ VERSION = '0.0.2'
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'opal/actionpack/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'opal-actionpack'
8
+ gem.version = Opal::Actionpack::VERSION
9
+ gem.authors = ['Steve Tuckner']
10
+ gem.email = ['stevetuckner@stewdle.com']
11
+ gem.licenses = ['MIT']
12
+ gem.description = %q{A small port of the glorious ActionPack for Opal}
13
+ gem.summary = %q{
14
+ This implements a subset of the rails/actionpack gem.
15
+ Currently it does some of the routing functionality,
16
+ and some rendering functionality. It doesn't do
17
+ forms yet.
18
+ }
19
+ gem.homepage = 'https://github.com/boberetezeke/opal-actionpack'
20
+ gem.rdoc_options << '--main' << 'README' <<
21
+ '--line-numbers' <<
22
+ '--include' << 'opal'
23
+
24
+ gem.files = `git ls-files`.split($/)
25
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
26
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
27
+ gem.require_paths = ['lib']
28
+
29
+ gem.add_dependency 'opal', ['>= 0.5.0', '< 1.0.0']
30
+ gem.add_development_dependency 'rake'
31
+ gem.add_development_dependency 'opal-rspec'
32
+ end
@@ -0,0 +1 @@
1
+ require 'action_pack/core'
@@ -0,0 +1,475 @@
1
+ class String
2
+ def capitalize
3
+ self[0..0].upcase + self[1..-1]
4
+ end
5
+
6
+ def singularize
7
+ if m = /^(.*)s$/.match(self)
8
+ return m[1]
9
+ end
10
+ self
11
+ end
12
+
13
+ def pluralize
14
+ self + "s"
15
+ end
16
+ end
17
+
18
+ module PathHandler
19
+ def resolve_path(root, *args)
20
+ @application.resolve_path(root, *args)
21
+ end
22
+
23
+ def method_missing(sym, *args, &block)
24
+ sym_to_s = sym.to_s
25
+ m = /^(.*)_path$/.match(sym_to_s)
26
+ if m
27
+ return @application.resolve_path(m[1], *args)
28
+ end
29
+
30
+ super
31
+ end
32
+ end
33
+
34
+ class ActionController
35
+ class Base
36
+ include PathHandler
37
+
38
+ attr_reader :params
39
+
40
+ def initialize(params)
41
+ @application = Application.instance
42
+ @params = params
43
+ end
44
+
45
+ def render_template
46
+ ActionView.new.render(self, file: render_path)
47
+ end
48
+
49
+ def invoke_action(action)
50
+ # set up default render path
51
+ @render_path = "views" + "/" + view_path + "/" + action.name
52
+ self.send(action.name)
53
+ end
54
+
55
+ def view_path
56
+ controller_parts = self.class.to_s.split(/::/)
57
+ controller_parts = controller_parts[0..-2].map{|part| part.downcase} + [controller_root_name(controller_parts[-1])]
58
+ controller_parts.join("/")
59
+ end
60
+
61
+ def controller_root_name(controller_name)
62
+ /^(.*)Controller$/.match(controller_name)[1].downcase
63
+ end
64
+
65
+ private
66
+
67
+ def render_path
68
+ @render_path
69
+ end
70
+ end
71
+ end
72
+
73
+ class ActionView
74
+ include PathHandler
75
+ attr_reader :absolute_path
76
+
77
+ INITIALIZE_DEFAULTS={locals: {}, path: ""}
78
+ def initialize(options={})
79
+ options = INITIALIZE_DEFAULTS.merge(options)
80
+ @path = options[:path]
81
+ @application = Application.instance
82
+ # Opal / RMI diff ("".split(/\//) == [""] vs []
83
+ if @path == ""
84
+ @path_parts = []
85
+ else
86
+ @path_parts = @path.split(/\//)
87
+ end
88
+ @locals = options[:locals]
89
+ @absolute_path = ""
90
+ end
91
+
92
+ def render(controller, options={}, locals={}, &block)
93
+ if options[:file]
94
+ render_path = options[:file]
95
+ @absolute_path = render_path
96
+ elsif options[:partial]
97
+ partial_parts = options[:partial].split(/\//)
98
+ render_path = (@path_parts + partial_parts[0..-2] + ["_" + partial_parts[-1]]).join("/")
99
+ elsif options[:text]
100
+ return options[:text]
101
+ end
102
+ @locals = locals
103
+ copy_instance_variables_from(controller)
104
+ Template[render_path].render(self)
105
+ end
106
+
107
+ def copy_instance_variables_from(object)
108
+ object.instance_variables.each do |ivar|
109
+ self.instance_variable_set(ivar, object.instance_variable_get(ivar))
110
+ end
111
+ end
112
+
113
+ def link_to(text, path, options={})
114
+ "<a href=\"#{path}\"" + options.map{|k,v| "#{k}=\"#{v}\""}.join(' ') + ">#{text}</a>"
115
+ end
116
+
117
+ def method_missing(sym, *args, &block)
118
+ sym_to_s = sym.to_s
119
+ if @locals.has_key?(sym_to_s)
120
+ return @locals[sym_to_s]
121
+ elsif @locals.has_key?(sym)
122
+ return @locals[sym]
123
+ end
124
+
125
+ super
126
+ end
127
+ end
128
+
129
+ class Application
130
+ class Router
131
+ def initialize
132
+ @routes = []
133
+ end
134
+
135
+ def draw
136
+ yield self
137
+ end
138
+
139
+ def resources(route, options={})
140
+ @routes.push(Route.new(route, options))
141
+ end
142
+
143
+ def match_url(url)
144
+ parts, params = to_parts(url)
145
+
146
+ @routes.each do |route|
147
+ #puts "matching parts=#{parts.inspect}, route=#{route.inspect}"
148
+ if action = route.match(parts, params)
149
+ return [action, params]
150
+ end
151
+ end
152
+
153
+ raise "no route matches #{url}"
154
+ end
155
+
156
+ def match_path(resource_name, action_name, *args)
157
+ @routes.each do |route|
158
+ action = route.match_path(resource_name, action_name, *args)
159
+ return action if action
160
+ end
161
+
162
+ raise "no route matches path #{resource_name}::#{action_name}"
163
+ end
164
+
165
+ def to_parts(url)
166
+ # remove leading '/'
167
+ if m = /^\/(.*)$/.match(url)
168
+ url = m[1]
169
+ end
170
+
171
+ # separate url on ?
172
+ if m = /^([^?]*)\?(.*)$/.match(url)
173
+ url = m[1]
174
+ keys_and_values = m[2].split(/&/)
175
+ params = {}
176
+ keys_and_values.each do |key_and_value|
177
+ key, value = key_and_value.split(/=/)
178
+ params[key] = value
179
+ end
180
+ else
181
+ params = {}
182
+ end
183
+
184
+ [url.split(/\//), params]
185
+ end
186
+ end
187
+
188
+ class Action
189
+ attr_reader :name
190
+ def initialize(route, action_type, name, parts)
191
+ @route = route
192
+ @action_type = action_type
193
+ @name = name
194
+ @parts = parts
195
+ end
196
+
197
+ def match(parts, params)
198
+ #puts "Action:match: parts: #{parts.inspect}, name: #{@name}, action_parts: #{@parts.inspect}"
199
+ return false if parts.size != @parts.size
200
+ return true if parts.size == 0
201
+
202
+ @parts.each_with_index do |part, index|
203
+ if part.class == String
204
+ return true if /#{part}/.match(parts[index])
205
+ else
206
+ param_key = part.keys.first
207
+ matcher = /(#{part.values.first})/
208
+ if m = matcher.match(parts[index])
209
+ params[param_key] = m[1]
210
+ return true
211
+ end
212
+ end
213
+ end
214
+ return false
215
+ end
216
+
217
+ def match_path(action_name, *args)
218
+ #puts "action_name = #{action_name}, name = #{@name}, args = #{args.inspect}"
219
+ params = {}
220
+ return [false, params] unless @name.to_s == action_name.to_s
221
+
222
+ if args.size > 0
223
+ if args.last.is_a?(Hash)
224
+ params = args.pop
225
+ end
226
+ end
227
+
228
+ if @action_type == :member
229
+ if args.size == 1
230
+ object = args.first
231
+ if object.class == String
232
+ object_id = object
233
+ else
234
+ object_id = object.id
235
+ end
236
+ #puts "object_id = #{object_id}, name = #{@name}"
237
+ #
238
+ if @name.to_s == 'show'
239
+ action_root = object_id.to_s
240
+ else
241
+ action_root = "#{object_id}/#{@name}"
242
+ end
243
+ return [action_root, params]
244
+ else
245
+ raise "requires one argument passed to member path"
246
+ end
247
+ else
248
+ if args.size == 0
249
+ #puts "Action#match_path: @name = #{@name}"
250
+ if @name.to_s == 'index'
251
+ # FIXME: need to url encode parameters
252
+ action_root = ""
253
+ else
254
+ action_root = @name
255
+ end
256
+ return [action_root, params]
257
+ else
258
+ raise "argument passed to collection path"
259
+ end
260
+ end
261
+ end
262
+
263
+ def invoke_controller(action, params, options)
264
+ if options[:render_view]
265
+ controller_class_name = "#{@route.name.capitalize}Controller"
266
+ controller_class = Object.const_get(controller_class_name)
267
+ controller = controller_class.new(params)
268
+ controller.invoke_action(action)
269
+ html = controller.render_template
270
+ Document.find(options[:selector]).html = html
271
+ end
272
+
273
+ controller_client_class_name = "#{@route.name.capitalize}ClientController"
274
+ begin
275
+ controller_client_class = Object.const_get(controller_client_class_name)
276
+ begin
277
+ controller_action_class = controller_client_class.const_get(action.name.capitalize)
278
+ controller_action = controller_action_class.new(params)
279
+ controller_action.add_bindings
280
+ rescue
281
+ puts "client class: #{controller_client_class_name}::#{action.name.capitalize} doesn't exist"
282
+ end
283
+ rescue
284
+ puts "client class: #{controller_client_class_name} doesn't exist"
285
+ end
286
+ end
287
+ end
288
+
289
+ class Route
290
+ ALL_COLLECTION_ACTIONS = [:index]
291
+ ALL_RESOURCE_ACTIONS = [:show, :new, :create, :edit, :update, :destroy]
292
+
293
+ attr_reader :name
294
+
295
+ def initialize(name, options)
296
+ @name = name.to_s
297
+ @actions = [
298
+ Action.new(self, :member, :show, [{id: '.*'}]),
299
+ Action.new(self, :collection, :new, ['new']),
300
+ Action.new(self, :member, :edit, [{id: '.*'}, 'edit']),
301
+ Action.new(self, :collection, :index, [])
302
+ ]
303
+ end
304
+
305
+ def match(parts, params)
306
+ #puts "Route:match: parts: #{parts}, name: #{@name}"
307
+ return nil unless @name == parts[0]
308
+ @actions.each do |action|
309
+ return action if action.match(parts[1..-1], params)
310
+ end
311
+ return nil
312
+ end
313
+
314
+ def match_path(resource_name, action_name, *args)
315
+ #puts "Route#match_path, name = #{@name}, resource_name = #{resource_name}"
316
+ return nil unless @name.to_s == resource_name.to_s
317
+ @actions.each do |action|
318
+ action_path, params = action.match_path(action_name, *args)
319
+ # FIXME: need to url encode parameters
320
+ params_string = params.map{|key, value| "#{key}=#{value}"}.join("&")
321
+
322
+ #puts "action_path = #{action_path}"
323
+ if action_path
324
+ if action_path == ""
325
+ url = "/#{resource_name}"
326
+ else
327
+ url = "/#{resource_name}/#{action_path}"
328
+ end
329
+
330
+ return params_string.empty? ? url : "#{url}?#{params_string}"
331
+ end
332
+ end
333
+ return nil
334
+ end
335
+ end
336
+
337
+ def self.routes
338
+ @routes ||= Router.new
339
+ end
340
+
341
+ def self.instance
342
+ return @@application if defined?(@@application)
343
+ @@application = new
344
+ end
345
+
346
+ def initialize
347
+ @memory_store = ActiveRecord::MemoryStore.new
348
+ ActiveRecord::Base.connection = @memory_store
349
+ end
350
+
351
+ def launch(initial_url, initial_objects)
352
+ begin
353
+ @objects = [initial_objects]
354
+ @objects.each { |object| object.save }
355
+ puts "memory_store = #{@memory_store.inspect}"
356
+ go_to_route(initial_url, render_view: false)
357
+ rescue Exception => e
358
+ puts "Exception: #{e}"
359
+ e.backtrace[0..10].each do |trace|
360
+ puts trace
361
+ end
362
+ end
363
+ end
364
+
365
+ def resolve_path(path, *args)
366
+ # FIXME: can't detect plural by checking for trailing 's'
367
+ m = /^((\w+)_)?((\w+?)(s)?)$/.match(path)
368
+ if m
369
+ action_with_underscore = m[1]
370
+ action = m[2]
371
+ resource = m[3]
372
+ resource_root = m[4]
373
+ is_plural = m[5]
374
+
375
+ #puts "matched pattern: #{m}, action = #{action.inspect}, resource = #{resource}, is_plural=#{is_plural.inspect}"
376
+ if action_with_underscore
377
+ #puts "multi part path, action = #{action}"
378
+ if !is_plural
379
+ resource = resource.pluralize
380
+ end
381
+ else
382
+ if is_plural
383
+ #puts "single part path, plural"
384
+ action = 'index'
385
+ else
386
+ #puts "single part path, singular"
387
+ resource = resource.pluralize
388
+ action = 'show'
389
+ end
390
+ end
391
+ else
392
+ raise "unable to match path: #{path}_path"
393
+ end
394
+
395
+ self.class.routes.match_path(resource, action, *args)
396
+ end
397
+
398
+ def go_to_route(url, options={})
399
+ @current_route_action, @params = self.class.routes.match_url(url)
400
+ @current_route_action.invoke_controller(@current_route_action, @params, options)
401
+ end
402
+
403
+ ROUTE_MAP = {
404
+ "Calculator" => {route: 'calculators', key: 'calculator'},
405
+ "Results" => {route: 'results', key: 'result'}
406
+ }
407
+
408
+ def connect
409
+ @memory_store.on_change do |change_type, object|
410
+ route = "/" + ROUTE_MAP[object.class.to_s][:route]
411
+ key = ROUTE_MAP[object.class.to_s][:key]
412
+ case change_type
413
+ when :insert
414
+ puts "INSERT: #{object}"
415
+ HTTP.post route, {:payload => {:key => object.to_json}}
416
+ when :delete
417
+ puts "DELETE: #{object}"
418
+ when :update
419
+ puts "UPDATE: #{object}"
420
+ HTTP.put "#{route}/#{object.id}", object.attributes do |response|
421
+ end
422
+ end
423
+ end
424
+ end
425
+ end
426
+
427
+ =begin
428
+ class Node
429
+ attr_reader :children
430
+ def initialize(name=nil)
431
+ @name = name
432
+ @children = []
433
+ end
434
+
435
+ def node(name, &block)
436
+ child = Node.new(name)
437
+ @children.push(child)
438
+ child.instance_exec(&block) if block
439
+ end
440
+
441
+ def instance_exec(*args, &block)
442
+ method_name = nil
443
+ n = 0
444
+ n += 1 while respond_to?(method_name = "__instance_exec#{n}")
445
+ self.class.instance_eval { define_method(method_name, &block) }
446
+
447
+ begin
448
+ send(method_name, *args)
449
+ ensure
450
+ self.class.instance_eval { remove_method(method_name) } rescue nil
451
+ end
452
+ end
453
+
454
+ def to_s
455
+
456
+ @name + "[" + @children.map{|child| child.to_s}.join(", ") + "]"
457
+ end
458
+ end
459
+
460
+ def tree(name, &block)
461
+ @tree = Node.new(name)
462
+ @tree.instance_exec(&block)
463
+ @tree
464
+ end
465
+
466
+ tree("Simpsons family tree") do
467
+ node("gramps") do
468
+ node("homer+marge") do
469
+ node("bart")
470
+ node("lisa")
471
+ node("maggie")
472
+ end
473
+ end
474
+ end
475
+ =end
@@ -0,0 +1 @@
1
+ require 'action_pack'
@@ -0,0 +1,301 @@
1
+ require 'spec_helper'
2
+
3
+ # mock up ActiveRecord
4
+ class ActiveRecord
5
+ class Base
6
+ def self.connection=(connection)
7
+ end
8
+ end
9
+
10
+ class MemoryStore
11
+ end
12
+ end
13
+
14
+ class CalculatorsController < ActionController::Base
15
+ def initialize(params={})
16
+ super
17
+ @ivar = 1
18
+ end
19
+ end
20
+
21
+ class Nested
22
+ class ResultsController < ActionController::Base
23
+ end
24
+ end
25
+
26
+ class CalculatorsClientController
27
+ class Show < ActionController::Base
28
+ def initialize(params)
29
+ super
30
+ end
31
+
32
+ def add_bindings
33
+ end
34
+
35
+ def invoke_callback
36
+ calculators_path(id:1)
37
+ end
38
+ end
39
+ end
40
+
41
+
42
+ if RUBY_ENGINE != "opal"
43
+ class Template
44
+ end
45
+ end
46
+
47
+ describe Application do
48
+ let(:object1) { double('object') }
49
+
50
+ describe "#launch" do
51
+ before do
52
+ Application.routes.draw do |router|
53
+ router.resources :calculators
54
+ router.resources :results
55
+ end
56
+ allow(object1).to receive(:save).and_return(nil)
57
+ end
58
+
59
+ context "when launching the application with a show action" do
60
+ it "should be true" do
61
+ =begin
62
+ show_controller = double('calculator_show_controller')
63
+ expect(CalculatorsController).to receive(:new).with({id: '1'}).and_return(show_controller)
64
+ expect(show_controller).to receive(:add_bindings)
65
+ application = Application.instance.launch("/calculators/1", object1)
66
+ =end
67
+ end
68
+ end
69
+ end
70
+
71
+ describe Application::Action do
72
+ describe "#match_path" do
73
+ let(:route) { double('route') }
74
+
75
+ it "matches if a show path with 1 arg" do
76
+ action = Application::Action.new(route, :member, 'show', {id: '.*'})
77
+ expect(action.match_path(:show, '1')).to eq(["1", {}])
78
+ end
79
+
80
+ it "matches if a show path with 1 arg and params" do
81
+ action = Application::Action.new(route, :member, 'show', {id: '.*'})
82
+ expect(action.match_path(:show, '1', extra: 1)).to eq(["1", {extra: 1}])
83
+ end
84
+
85
+ it "matches if a non-show member path with 1 arg" do
86
+ action = Application::Action.new(route, :member, 'edit', {id: '.*'})
87
+ expect(action.match_path(:edit, '1')).to eq(["1/edit", {}])
88
+ end
89
+
90
+ it "matches if a index path with 0 args" do
91
+ action = Application::Action.new(route, :collection, 'index', {id: '.*'})
92
+ expect(action.match_path(:index)).to eq(["", {}])
93
+ end
94
+
95
+ it "matches if a index path with params as args" do
96
+ action = Application::Action.new(route, :collection, 'index', {id: '.*'})
97
+ expect(action.match_path(:index, extra: 1)).to eq(["", {extra: 1}])
98
+ end
99
+
100
+ it "matches if a non-index collection path with 0 args" do
101
+ action = Application::Action.new(route, :collection, 'new', {id: '.*'})
102
+ expect(action.match_path(:new)).to eq(["new", {}])
103
+ end
104
+
105
+ #it "raises an exception with a member path without 1 arg"
106
+ #it "raises an exception with a collection path without 0 args"
107
+ end
108
+
109
+ #describe "#match"
110
+ end
111
+
112
+ describe Application::Route do
113
+ describe "#match_path" do
114
+ it "matches a show path" do
115
+ route = Application::Route.new("calculators", {})
116
+ expect(route.match_path("calculators", "show", "1")).to eq("/calculators/1")
117
+ end
118
+
119
+ it "matches a non-show member path" do
120
+ route = Application::Route.new("calculators", {})
121
+ expect(route.match_path("calculators", "edit", "1")).to eq("/calculators/1/edit")
122
+ end
123
+
124
+ it "matches an index path" do
125
+ route = Application::Route.new("calculators", {})
126
+ expect(route.match_path("calculators", "index")).to eq("/calculators")
127
+ end
128
+
129
+ it "matches an non-index collection path" do
130
+ route = Application::Route.new("calculators", {})
131
+ expect(route.match_path("calculators", "new")).to eq("/calculators/new")
132
+ end
133
+
134
+ #describe "#match"
135
+
136
+ end
137
+ end
138
+
139
+ describe Application::Router do
140
+ before do
141
+ Application.routes.draw do |router|
142
+ router.resources :calculators
143
+ router.resources :results
144
+ end
145
+ end
146
+
147
+ describe "#match_path" do
148
+ it "matches a show path" do
149
+ expect(Application.routes.match_path("calculators", "show", "1")).to eq("/calculators/1")
150
+ end
151
+
152
+ it "matches a non-show member path" do
153
+ expect(Application.routes.match_path("results", "edit", "1")).to eq("/results/1/edit")
154
+ end
155
+
156
+ it "matches an index path" do
157
+ expect(Application.routes.match_path("results", "index")).to eq("/results")
158
+ end
159
+
160
+ it "matches an non-index collection path" do
161
+ expect(Application.routes.match_path("calculators", "new")).to eq("/calculators/new")
162
+ end
163
+ end
164
+
165
+ #describe "#draw"
166
+ #describe "#resources"
167
+ #describe "#match_url"
168
+ #describe "#to_parts"
169
+ end
170
+ end
171
+
172
+ describe ActionView do
173
+ before do
174
+ Application.routes.draw do |router|
175
+ router.resources :calculators
176
+ router.resources :results
177
+ end
178
+ end
179
+
180
+ describe "#render" do
181
+ let(:template) { double('template') }
182
+
183
+ before do
184
+ @controller = CalculatorsController.new
185
+ end
186
+
187
+ it "renders from files" do
188
+ action_view = ActionView.new
189
+ expect(template).to receive(:render).with(action_view)
190
+ expect(Template).to receive(:[]).with("a/b/c").and_return(template)
191
+ action_view.render(@controller, file: "a/b/c")
192
+
193
+ expect(action_view.instance_variable_get(:@ivar)).to eq(1)
194
+ end
195
+
196
+ context "when doing a partial" do
197
+ it "renders from single-directory path partials" do
198
+ action_view = ActionView.new(path: "a/b")
199
+ expect(template).to receive(:render).with(action_view)
200
+ expect(Template).to receive(:[]).with("a/b/_c").and_return(template)
201
+ action_view.render(@controller, partial: "c")
202
+ end
203
+
204
+ it "renders from multi-directory path partials" do
205
+ action_view = ActionView.new
206
+ expect(template).to receive(:render).with(action_view)
207
+ expect(Template).to receive(:[]).with("a/b/_c").and_return(template)
208
+ action_view.render(@controller, partial: "a/b/c")
209
+ end
210
+ end
211
+
212
+ it "renders from text" do
213
+ action_view = ActionView.new
214
+ expect(action_view.render(@controller, text: "hello")).to eq("hello")
215
+ end
216
+ end
217
+
218
+ describe "#link_to" do
219
+ # it should generate an anchor link with and without options
220
+ end
221
+
222
+ describe "#resolve_path" do
223
+ it "should match a show path" do
224
+ action_view = ActionView.new
225
+ expect(action_view.resolve_path('calculator', "1")).to eq("/calculators/1")
226
+ end
227
+ end
228
+
229
+ describe "#method_missing" do
230
+ it "should handle show _path method" do
231
+ action_view = ActionView.new
232
+ expect(action_view.calculator_path("1")).to eq("/calculators/1")
233
+ end
234
+
235
+ it "should handle show _path method with params" do
236
+ action_view = ActionView.new
237
+ expect(action_view.calculator_path("1", extra: 1)).to eq("/calculators/1?extra=1")
238
+ end
239
+
240
+ it "should handle a non-show member _path method" do
241
+ action_view = ActionView.new
242
+ expect(action_view.edit_calculator_path("1")).to eq("/calculators/1/edit")
243
+ end
244
+
245
+ it "should handle a index _path method" do
246
+ action_view = ActionView.new
247
+ expect(action_view.calculators_path).to eq("/calculators")
248
+ end
249
+
250
+ it "should handle a index _path method with params" do
251
+ action_view = ActionView.new
252
+ expect(action_view.calculators_path(extra: 1)).to eq("/calculators?extra=1")
253
+ end
254
+
255
+ it "should handle a non-index collection _path method" do
256
+ action_view = ActionView.new
257
+ expect(action_view.new_calculators_path).to eq("/calculators/new")
258
+ end
259
+
260
+ it "should handle references to locals" do
261
+ action_view = ActionView.new(locals: { test_var: 1})
262
+ expect(action_view.test_var).to eq(1)
263
+ end
264
+ end
265
+ end
266
+
267
+ describe ActionController::Base do
268
+ before do
269
+ Application.routes.draw do |router|
270
+ router.resources :calculators
271
+ router.resources :results
272
+ end
273
+ end
274
+
275
+ describe "#action_method" do
276
+ it "should resolve_paths in the application" do
277
+ expect(Application.instance).to receive(:resolve_path)
278
+ calculators_controller = CalculatorsClientController::Show.new({})
279
+ calculators_controller.invoke_callback
280
+ end
281
+ end
282
+
283
+ describe "#view_path" do
284
+ it "should return the path to the view on a sinple controller" do
285
+ controller = CalculatorsController.new({})
286
+ expect(controller.view_path).to eq("calculators")
287
+ end
288
+
289
+ it "should return the path to the view on a sinple controller" do
290
+ controller = Nested::ResultsController.new({})
291
+ expect(controller.view_path).to eq("nested/results")
292
+ end
293
+ end
294
+
295
+ describe "#controller_root_name" do
296
+ it "should return a downcased name fo the controller class's root name" do
297
+ controller = CalculatorsController.new({})
298
+ expect(controller.controller_root_name("CalculatorsController")).to eq("calculators")
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,17 @@
1
+ if RUBY_ENGINE == "opal"
2
+ require 'opal-rspec'
3
+ require 'opal-actionpack'
4
+ else
5
+ require_relative '../opal/action_pack/core'
6
+ end
7
+
8
+ module TestUnitHelpers
9
+ def assert_equal actual, expected
10
+ actual.should == expected
11
+ end
12
+ end
13
+
14
+ RSpec.configure do |config|
15
+ config.include TestUnitHelpers
16
+ end
17
+
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opal-actionpack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Steve Tuckner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: opal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.0
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.5.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: rake
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: opal-rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ description: A small port of the glorious ActionPack for Opal
62
+ email:
63
+ - stevetuckner@stewdle.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - .gitignore
69
+ - Gemfile
70
+ - Gemfile.lock
71
+ - LICENSE
72
+ - LICENSE.txt
73
+ - README.md
74
+ - Rakefile
75
+ - lib/opal-actionpack.rb
76
+ - lib/opal/actionpack.rb
77
+ - lib/opal/actionpack/version.rb
78
+ - opal-actionpack.gemspec
79
+ - opal/action_pack.rb
80
+ - opal/action_pack/core.rb
81
+ - opal/opal-actionpack.rb
82
+ - spec/actionpack_spec.rb
83
+ - spec/spec_helper.rb
84
+ homepage: https://github.com/boberetezeke/opal-actionpack
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options:
90
+ - --main
91
+ - README
92
+ - --line-numbers
93
+ - --include
94
+ - opal
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.0.3
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: This implements a subset of the rails/actionpack gem. Currently it does some
113
+ of the routing functionality, and some rendering functionality. It doesn't do forms
114
+ yet.
115
+ test_files:
116
+ - spec/actionpack_spec.rb
117
+ - spec/spec_helper.rb