opal-actionpack 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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