wedge 0.1.17 → 0.1.18
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 +4 -4
- data/Gemfile +8 -1
- data/Makefile +2 -0
- data/Rakefile +8 -4
- data/TODO.md +4 -0
- data/lib/roda/plugins/wedge.rb +14 -96
- data/lib/wedge.rb +9 -4
- data/lib/wedge/component.rb +70 -29
- data/lib/wedge/config.rb +36 -6
- data/lib/wedge/middleware.rb +43 -35
- data/lib/wedge/opal.rb +15 -4
- data/lib/wedge/plugins/ability_list.rb +95 -0
- data/lib/wedge/plugins/current_user.rb +48 -0
- data/lib/wedge/plugins/factory.rb +36 -0
- data/lib/wedge/plugins/form.rb +216 -343
- data/lib/wedge/plugins/{validations.rb → form/validations.rb} +64 -37
- data/lib/wedge/plugins/form_backup.rb +442 -0
- data/lib/wedge/plugins/render.rb +110 -0
- data/lib/wedge/plugins/uploader.rb +2 -2
- data/lib/wedge/utilis/duplicable.rb +104 -0
- data/lib/wedge/utilis/hash.rb +48 -0
- data/lib/wedge/version.rb +1 -1
- data/playground/app/app.rb +27 -11
- data/playground/app/components/abilities.rb +11 -0
- data/playground/app/components/current_user.rb +12 -0
- data/playground/app/components/layout.rb +5 -0
- data/playground/app/components/todo_list.rb +24 -0
- data/playground/app/config/boot.rb +3 -0
- data/playground/app/forms/todo_list_add.rb +9 -0
- data/playground/app/models/user.rb +5 -0
- data/playground/public/css/styles.css +139 -0
- data/playground/public/css/todo_list.css +138 -0
- data/playground/public/todo_list.html +23 -0
- data/playground/src/css/styles.scss +2 -1
- data/playground/src/css/todo_list.scss +165 -0
- data/playground/src/todo_list.slim +17 -0
- data/spec/playground/uploader_spec.rb +27 -29
- data/spec/spec_helper.rb +29 -0
- data/spec/stubs/models/user.rb +15 -0
- data/spec/wedge/plugins/current_user_spec.rb +29 -0
- data/spec/wedge/plugins/factory_spec.rb +16 -0
- data/spec/wedge/plugins/form_spec.rb +119 -0
- data/spec/wedge/plugins/uploader_spec.rb +1 -3
- data/spec/wedge_spec.rb +3 -3
- metadata +28 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d5cba344b9b2d2cb5555b9eaf30132afd576c85
|
4
|
+
data.tar.gz: 3f13558b89e8a9d960b417f7e792b96385e56992
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d5d9ebb80b5aaf32d7bf2fa688176e34b45cfadb39eabdd58c5863351abbd0b5bfc1918ebf98dcd021d47a640742bac0c63fe566b7446fee3e55ea9c79e387b
|
7
|
+
data.tar.gz: 428783e6058d34db64e503538d29851d04274570db989afa3775daf5b8d48148aa74bb2e229eab776102b99b06be09c89e0e35fb8e1e50b9c773834886b1d3bc
|
data/Gemfile
CHANGED
@@ -5,10 +5,17 @@ gemspec
|
|
5
5
|
|
6
6
|
gem 'opal', github: 'opal/opal'
|
7
7
|
gem 'opal-jquery', github: 'opal/opal-jquery'
|
8
|
-
gem 'opal-rspec
|
8
|
+
gem 'opal-rspec-cj'
|
9
9
|
gem 'binding_of_caller'
|
10
10
|
gem 'better_errors'
|
11
11
|
gem 'slim'
|
12
12
|
gem 'sass'
|
13
13
|
gem 'thin'
|
14
|
+
gem 'roda', '2.4.0'
|
15
|
+
gem 'pry-rescue'
|
16
|
+
gem 'pry-stack_explorer'
|
17
|
+
# issue: https://github.com/copiousfreetime/hitimes/issues/17
|
18
|
+
gem 'hitimes', '1.2.1'
|
19
|
+
gem 'restart'
|
20
|
+
gem 'rack_csrf', '2.5.0'
|
14
21
|
gem 'roda-bin'
|
data/Makefile
ADDED
data/Rakefile
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
$:.unshift(File.expand_path('./lib'))
|
2
2
|
$:.unshift(File.expand_path("./playground/app"))
|
3
3
|
|
4
|
+
current_task = Rake.application.top_level_tasks.first
|
5
|
+
|
6
|
+
ENV['RACK_ENV'] ||= (current_task['default'] || current_task[/(rspec|test)\z/]) ? 'test' : 'development'
|
7
|
+
|
4
8
|
require 'bundler'
|
5
9
|
require 'bundler/gem_tasks'
|
6
10
|
require 'bundler/setup'
|
7
11
|
|
8
12
|
require 'config/boot'
|
9
|
-
require '
|
13
|
+
require 'tilt/erubis'
|
10
14
|
require 'opal/rspec/rake_task'
|
11
15
|
|
12
16
|
Opal.append_path File.expand_path('../lib', __FILE__)
|
13
17
|
Opal.append_path File.expand_path('../playground/app', __FILE__)
|
14
18
|
Opal.append_path File.expand_path('../playground/public', __FILE__)
|
15
19
|
|
16
|
-
Opal::RSpec::RakeTask.new('opal:rspec') do |s|
|
20
|
+
Opal::RSpec::RakeTask.new('opal:rspec', Playground) do |s|
|
17
21
|
s.index_path = 'spec/index.html.erb'
|
18
22
|
end
|
19
23
|
|
@@ -23,8 +27,8 @@ require 'rspec/core/rake_task'
|
|
23
27
|
RSpec::Core::RakeTask.new('ruby:rspec')
|
24
28
|
|
25
29
|
task :test do
|
30
|
+
puts "--------------------------\nRun specs in Ruby\n--------------------------"
|
31
|
+
Rake::Task['ruby:rspec'].invoke
|
26
32
|
puts "--------------------------\nRun specs in Opal\n--------------------------"
|
27
33
|
Rake::Task['opal:rspec'].invoke
|
28
|
-
puts "--------------------------\nRun specs in normal ruby\n--------------------------"
|
29
|
-
Rake::Task['ruby:rspec'].invoke
|
30
34
|
end
|
data/TODO.md
ADDED
data/lib/roda/plugins/wedge.rb
CHANGED
@@ -1,121 +1,39 @@
|
|
1
1
|
class Roda
|
2
2
|
module RodaPlugins
|
3
|
-
class
|
4
|
-
def self.configure(app, opts =
|
5
|
-
if
|
6
|
-
app.opts
|
3
|
+
class WedgePlugin
|
4
|
+
def self.configure(app, opts = false, &block)
|
5
|
+
if !opts || !opts.delete(:disable_middleware)
|
6
|
+
app.use Wedge::Middleware, opts || block
|
7
7
|
else
|
8
|
-
|
8
|
+
opts.each { |k, v| Wedge.config.send "#{k}=", v }
|
9
9
|
end
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
case k.to_s
|
15
|
-
when 'plugins'
|
16
|
-
v.each { |p| ::Wedge.config.plugin p }
|
17
|
-
when 'scope'
|
18
|
-
begin
|
19
|
-
::Wedge.config.scope = v.new
|
20
|
-
rescue
|
21
|
-
::Wedge.config.scope = v.new({})
|
22
|
-
end
|
23
|
-
else
|
24
|
-
::Wedge.config.send "#{k}=", v
|
25
|
-
end
|
12
|
+
module ClassMethods
|
13
|
+
def wedge_plugin name, settings = {}, &block
|
14
|
+
Wedge.plugin name, settings, &block
|
26
15
|
end
|
27
|
-
|
28
|
-
# cache the javascript on load
|
29
|
-
::Wedge.javascript if opts[:cache_assets]
|
30
16
|
end
|
31
17
|
|
32
18
|
module InstanceMethods
|
33
19
|
def wedge(name, *args, &block)
|
34
|
-
|
20
|
+
Wedge.scope!(self)[name, *args, &block]
|
35
21
|
end
|
36
22
|
|
37
23
|
def wedge_plugin(name, *args, &block)
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
module RequestClassMethods
|
43
|
-
def wedge_route_regex
|
44
|
-
assets_url = ::Wedge.assets_url.gsub(%r{^\/}, '')
|
45
|
-
# # We also allow for no assets key so when we post server methods there
|
46
|
-
# # isn't an error if the key has been changed since a browser refresh.
|
47
|
-
%r{(?:#{assets_url}|#{assets_url.sub("#{::Wedge.config.assets_key}/", '')})/(.*)\.(.*)$}
|
24
|
+
Wedge.scope!(self)["#{name}_plugin", *args, &block]
|
48
25
|
end
|
49
26
|
end
|
50
27
|
|
51
28
|
module RequestMethods
|
52
29
|
def wedge_assets
|
53
|
-
on
|
54
|
-
|
55
|
-
when 'map'
|
56
|
-
::Wedge.source_map component
|
57
|
-
when 'rb'
|
58
|
-
if component =~ /^wedge/
|
59
|
-
path = ::Wedge.config.path.gsub(/\/wedge.rb$/, '')
|
60
|
-
File.read("#{path}/#{component}.rb")
|
61
|
-
else
|
62
|
-
File.read("#{component}.rb")
|
63
|
-
end
|
64
|
-
when 'call'
|
65
|
-
body = scope.request.body.read
|
66
|
-
data = scope.request.params
|
67
|
-
|
68
|
-
begin
|
69
|
-
# try json
|
70
|
-
data.merge!(body ? JSON.parse(body) : {})
|
71
|
-
rescue
|
72
|
-
begin
|
73
|
-
# try form data
|
74
|
-
data.merge!(body ? Rack::Utils.parse_query(body) : {})
|
75
|
-
rescue
|
76
|
-
# no data
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
data = data.indifferent
|
81
|
-
name = data.delete(:__wedge_name__)
|
82
|
-
method_called = data.delete(:__wedge_method__)
|
83
|
-
method_args = data.delete(:__wedge_args__)
|
84
|
-
|
85
|
-
if method_args == '__wedge_data__' && data
|
86
|
-
method_args = [data]
|
87
|
-
res = scope.wedge(name).send(method_called, *method_args) || ''
|
88
|
-
else
|
89
|
-
# This used to send things like init, we need a better way to
|
90
|
-
# send client config data to the server
|
91
|
-
# res = scope.wedge(name, data).send(method_called, *method_args) || ''
|
92
|
-
res = scope.wedge(name).send(method_called, *method_args) || ''
|
93
|
-
end
|
94
|
-
|
95
|
-
scope.response.headers["WEDGE-CSRF-TOKEN"] = scope.csrf_token if scope.methods.include? :csrf_token
|
96
|
-
|
97
|
-
if res.is_a? Hash
|
98
|
-
scope.response.headers["Content-Type"] = 'application/json; charset=UTF-8'
|
99
|
-
res = res.to_json
|
100
|
-
else
|
101
|
-
res = res.to_s
|
102
|
-
end
|
103
|
-
|
104
|
-
res
|
105
|
-
else
|
106
|
-
scope.response.headers['Content-Type'] = 'application/javascript; charset=UTF-8'
|
107
|
-
|
108
|
-
if ::Wedge.config.debug
|
109
|
-
"#{::Wedge.javascript(component)}\n//# sourceMappingURL=/assets/wedge/#{component}.map"
|
110
|
-
else
|
111
|
-
::Wedge.javascript(component)
|
112
|
-
end
|
113
|
-
end
|
30
|
+
on Wedge.assets_url_regex do
|
31
|
+
run @@__wedge_middleware__ ||= Wedge::Middleware.scope!(scope).new
|
114
32
|
end
|
115
33
|
end
|
116
34
|
end
|
117
35
|
end
|
118
36
|
|
119
|
-
register_plugin(:wedge,
|
37
|
+
register_plugin(:wedge, WedgePlugin)
|
120
38
|
end
|
121
39
|
end
|
data/lib/wedge.rb
CHANGED
@@ -8,6 +8,7 @@ require 'wedge/utilis/try'
|
|
8
8
|
require 'wedge/utilis/titleize'
|
9
9
|
require 'wedge/utilis/element'
|
10
10
|
require 'base64'
|
11
|
+
require 'forwardable'
|
11
12
|
unless RUBY_ENGINE == 'opal'
|
12
13
|
require 'nokogiri'
|
13
14
|
require 'wedge/utilis/nokogiri'
|
@@ -23,10 +24,14 @@ class Wedge
|
|
23
24
|
include Methods
|
24
25
|
|
25
26
|
class << self
|
27
|
+
extend Forwardable
|
28
|
+
|
26
29
|
ATTR_ACCESSORS = %i{scope store config events}
|
27
30
|
|
28
31
|
attr_accessor(*ATTR_ACCESSORS)
|
29
32
|
|
33
|
+
delegate [:plugin] => :config
|
34
|
+
|
30
35
|
def assets_url
|
31
36
|
url = config.assets_url.gsub(%r{^(http(|s)://[^\/]*\/|\/)}, '/')
|
32
37
|
"#{url}#{config.cache_assets ? "/#{config.assets_key}" : ''}"
|
@@ -91,17 +96,17 @@ class Wedge
|
|
91
96
|
#
|
92
97
|
# @param name [String, Symbol, #to_s] The unique name given to a component.
|
93
98
|
# @return [Wedge::Component#method] Last line of the method called.
|
94
|
-
def [](
|
95
|
-
config.component_class[
|
99
|
+
def [](*args, &block)
|
100
|
+
config.component_class[args.shift].wedge_new self, *args, &block
|
96
101
|
end
|
97
102
|
|
98
103
|
%w(store scope).each do |meth|
|
99
104
|
define_method "#{meth}!" do |value|
|
100
105
|
klass = Class.new(self)
|
101
106
|
ATTR_ACCESSORS.each do |name|
|
102
|
-
klass.instance_variable_set(:"@#{name}", Wedge.instance_variable_get(:"@#{name}"))
|
107
|
+
klass.instance_variable_set(:"@#{name}", Wedge.instance_variable_get(:"@#{name}").deep_dup)
|
103
108
|
end
|
104
|
-
klass.instance_variable_set(:"@#{meth}", value)
|
109
|
+
klass.instance_variable_set(:"@#{meth}", value.deep_dup)
|
105
110
|
klass
|
106
111
|
end
|
107
112
|
end
|
data/lib/wedge/component.rb
CHANGED
@@ -32,6 +32,10 @@ class Wedge
|
|
32
32
|
obj
|
33
33
|
end
|
34
34
|
|
35
|
+
def plugin *args
|
36
|
+
Wedge.plugin *args
|
37
|
+
end
|
38
|
+
|
35
39
|
alias_method :original_name, :name
|
36
40
|
def wedge_name(*args)
|
37
41
|
if args.any?
|
@@ -113,7 +117,7 @@ class Wedge
|
|
113
117
|
alias_method :dom, :wedge_dom
|
114
118
|
|
115
119
|
def wedge_config
|
116
|
-
@wedge_config ||= Config.new Wedge.config.
|
120
|
+
@wedge_config ||= Config.new klass: self, scope: Wedge.config.scope
|
117
121
|
end
|
118
122
|
alias_method :config, :wedge_config
|
119
123
|
|
@@ -181,25 +185,50 @@ class Wedge
|
|
181
185
|
# refreshed the browser yet.
|
182
186
|
call_url = "#{Wedge.assets_url.sub("#{Wedge.config.assets_key}/",'')}/#{path_name}.call"
|
183
187
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
188
|
+
if block_given?
|
189
|
+
HTTP.post(call_url,
|
190
|
+
headers: {
|
191
|
+
'X-CSRF-TOKEN' => Element.find('meta[name=_csrf]').attr('content'),
|
192
|
+
'X-WEDGE-METHOD-REQUEST' => meth
|
193
|
+
},
|
194
|
+
async: false,
|
195
|
+
payload: payload) do |response|
|
196
|
+
|
197
|
+
# We set the new csrf token
|
198
|
+
xhr = Native(response.xhr)
|
199
|
+
# discuss: I don't think we should update the csrf token every ajax call
|
200
|
+
# csrf = xhr.getResponseHeader('WEDGE-CSRF-TOKEN')
|
201
|
+
# Element.find('meta[name=_csrf]').attr 'content', csrf
|
202
|
+
###########################
|
203
|
+
|
204
|
+
res = JSON.from_object(`response`)
|
205
|
+
|
206
|
+
blk.call res[:body], res
|
207
|
+
end
|
208
|
+
else
|
209
|
+
data = {
|
210
|
+
headers: {
|
211
|
+
'X-CSRF-TOKEN' => "#{Element.find('meta[name=_csrf]').attr('content')}",
|
212
|
+
'X-WEDGE-METHOD-REQUEST' => meth
|
213
|
+
},
|
214
|
+
dataType: 'json',
|
215
|
+
type: 'POST',
|
216
|
+
url: call_url,
|
217
|
+
data: payload,
|
218
|
+
async: false
|
219
|
+
}.to_n
|
220
|
+
|
221
|
+
response = `$.ajax(data).responseText`
|
222
|
+
begin
|
223
|
+
JSON.parse response
|
224
|
+
rescue
|
225
|
+
if response.empty?
|
226
|
+
raise "Ajax response to #{call_url} was empty."
|
227
|
+
else
|
228
|
+
puts response
|
229
|
+
end
|
230
|
+
end
|
200
231
|
end
|
201
|
-
|
202
|
-
true
|
203
232
|
end
|
204
233
|
end
|
205
234
|
|
@@ -220,14 +249,17 @@ class Wedge
|
|
220
249
|
end
|
221
250
|
end
|
222
251
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
252
|
+
# We want the scope to override this method if defined
|
253
|
+
def wedge(*args, &block)
|
254
|
+
# fix: can't pass block to Wedge, opal error:
|
255
|
+
# https://github.com/opal/opal/issues/959
|
256
|
+
# scope.respond_to?(:wedge) ? scope.wedge(*args, &block) : Wedge[*args, &block]
|
257
|
+
scope.respond_to?(:wedge) ? scope.wedge(*args, &block) : Wedge[*args]
|
258
|
+
end
|
227
259
|
|
228
|
-
|
229
|
-
|
230
|
-
|
260
|
+
# We want the scope to override this method if defined
|
261
|
+
def wedge_plugin(name, *args, &block)
|
262
|
+
scope.respond_to?(:wedge_plugin) ? scope.wedge_plugin(*args, &block) : wedge("#{name}_plugin", *args, &block)
|
231
263
|
end
|
232
264
|
|
233
265
|
def wedge_scope
|
@@ -240,10 +272,15 @@ class Wedge
|
|
240
272
|
end
|
241
273
|
alias_method :store, :wedge_store
|
242
274
|
|
275
|
+
def wedge_class_store
|
276
|
+
self.class.wedge_config.store
|
277
|
+
end
|
278
|
+
alias_method :class_store, :wedge_class_store
|
279
|
+
|
243
280
|
# Duplicate of class condig [Config]
|
244
281
|
# @return config [Config]
|
245
282
|
def wedge_config
|
246
|
-
@wedge_config ||= Config.new(self.class.wedge_config.data.
|
283
|
+
@wedge_config ||= Config.new(self.class.wedge_config.data.deep_dup)
|
247
284
|
end
|
248
285
|
alias_method :config, :wedge_config
|
249
286
|
|
@@ -294,12 +331,16 @@ class Wedge
|
|
294
331
|
alias_method :function, :wedge_function
|
295
332
|
|
296
333
|
def wedge_from_server?
|
297
|
-
!
|
334
|
+
begin; !request.try(:env).include?('HTTP_X_WEDGE_METHOD_REQUEST'); rescue; true end
|
298
335
|
end
|
299
336
|
alias_method :from_server?, :wedge_from_server?
|
300
337
|
|
301
338
|
def wedge_from_client?
|
302
|
-
|
339
|
+
begin
|
340
|
+
caller_locations(1,1)[0].label == request.try(:env)['HTTP_X_WEDGE_METHOD_REQUEST']
|
341
|
+
rescue
|
342
|
+
false
|
343
|
+
end
|
303
344
|
end
|
304
345
|
alias_method :from_client?, :wedge_from_client?
|
305
346
|
|
data/lib/wedge/config.rb
CHANGED
@@ -16,12 +16,14 @@ class Wedge
|
|
16
16
|
path: nil,
|
17
17
|
html: nil,
|
18
18
|
scope: nil,
|
19
|
+
block: nil,
|
19
20
|
debug: false,
|
20
21
|
app_dir: 'app',
|
21
22
|
assets_url: '/assets/wedge',
|
22
23
|
assets_key: nil,
|
23
24
|
cache_assets: false,
|
24
25
|
is_plugin: false,
|
26
|
+
compile_str: false,
|
25
27
|
requires: IndifferentHash.new,
|
26
28
|
triggered_browser_events: false,
|
27
29
|
store: IndifferentHash.new,
|
@@ -41,17 +43,45 @@ class Wedge
|
|
41
43
|
@data.dup.select {|k, v| allowed_client_data.include? k }
|
42
44
|
end
|
43
45
|
|
44
|
-
def plugin(name)
|
46
|
+
def plugin(name, settings = {}, &block)
|
47
|
+
plugin_name = "#{name}_plugin"
|
48
|
+
|
49
|
+
Wedge.config.settings[plugin_name] = settings
|
50
|
+
|
45
51
|
unless RUBY_ENGINE == 'opal'
|
46
52
|
require "wedge/plugins/#{name}"
|
47
53
|
end
|
48
54
|
|
49
|
-
klass = Wedge.config.component_class[
|
50
|
-
|
55
|
+
klass = Wedge.config.component_class[plugin_name]
|
56
|
+
|
57
|
+
unless plugins.include? klass.config.path
|
58
|
+
klass.config.settings = settings
|
59
|
+
klass.config.block = block
|
60
|
+
klass.config.is_plugin = true
|
51
61
|
|
52
|
-
|
53
|
-
|
54
|
-
|
62
|
+
plugins << klass.config.path
|
63
|
+
plugins.uniq!
|
64
|
+
|
65
|
+
# Merge in instance/class methods
|
66
|
+
Wedge::Component.send(:include, klass::InstanceMethods) if defined?(klass::InstanceMethods)
|
67
|
+
Wedge::Component.extend(klass::ClassMethods) if defined?(klass::ClassMethods)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def plugins= plugins
|
72
|
+
plugins.each { |p| plugin(p.to_s) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def scope= value
|
76
|
+
if value.respond_to? :new
|
77
|
+
begin
|
78
|
+
@data.scope = value.new
|
79
|
+
rescue
|
80
|
+
@data.scope = value.new({})
|
81
|
+
end
|
82
|
+
else
|
83
|
+
@data.scope = value
|
84
|
+
end
|
55
85
|
end
|
56
86
|
|
57
87
|
def method_missing(method, *args, &block)
|