wedge 0.1.17 → 0.1.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +8 -1
  3. data/Makefile +2 -0
  4. data/Rakefile +8 -4
  5. data/TODO.md +4 -0
  6. data/lib/roda/plugins/wedge.rb +14 -96
  7. data/lib/wedge.rb +9 -4
  8. data/lib/wedge/component.rb +70 -29
  9. data/lib/wedge/config.rb +36 -6
  10. data/lib/wedge/middleware.rb +43 -35
  11. data/lib/wedge/opal.rb +15 -4
  12. data/lib/wedge/plugins/ability_list.rb +95 -0
  13. data/lib/wedge/plugins/current_user.rb +48 -0
  14. data/lib/wedge/plugins/factory.rb +36 -0
  15. data/lib/wedge/plugins/form.rb +216 -343
  16. data/lib/wedge/plugins/{validations.rb → form/validations.rb} +64 -37
  17. data/lib/wedge/plugins/form_backup.rb +442 -0
  18. data/lib/wedge/plugins/render.rb +110 -0
  19. data/lib/wedge/plugins/uploader.rb +2 -2
  20. data/lib/wedge/utilis/duplicable.rb +104 -0
  21. data/lib/wedge/utilis/hash.rb +48 -0
  22. data/lib/wedge/version.rb +1 -1
  23. data/playground/app/app.rb +27 -11
  24. data/playground/app/components/abilities.rb +11 -0
  25. data/playground/app/components/current_user.rb +12 -0
  26. data/playground/app/components/layout.rb +5 -0
  27. data/playground/app/components/todo_list.rb +24 -0
  28. data/playground/app/config/boot.rb +3 -0
  29. data/playground/app/forms/todo_list_add.rb +9 -0
  30. data/playground/app/models/user.rb +5 -0
  31. data/playground/public/css/styles.css +139 -0
  32. data/playground/public/css/todo_list.css +138 -0
  33. data/playground/public/todo_list.html +23 -0
  34. data/playground/src/css/styles.scss +2 -1
  35. data/playground/src/css/todo_list.scss +165 -0
  36. data/playground/src/todo_list.slim +17 -0
  37. data/spec/playground/uploader_spec.rb +27 -29
  38. data/spec/spec_helper.rb +29 -0
  39. data/spec/stubs/models/user.rb +15 -0
  40. data/spec/wedge/plugins/current_user_spec.rb +29 -0
  41. data/spec/wedge/plugins/factory_spec.rb +16 -0
  42. data/spec/wedge/plugins/form_spec.rb +119 -0
  43. data/spec/wedge/plugins/uploader_spec.rb +1 -3
  44. data/spec/wedge_spec.rb +3 -3
  45. metadata +28 -3
@@ -0,0 +1,110 @@
1
+ class Wedge
2
+ module Plugins
3
+ module Render
4
+ def display_errors options = {}, &block
5
+ dom = options.delete(:dom) || _options[:dom]
6
+ d_errors = errors
7
+
8
+ if override_errors = options[:override_errors]
9
+ d_errors = override_errors
10
+ end
11
+
12
+ keys = options.delete(:keys) || (_options[:key] ? [_options[:key]] : [])
13
+
14
+ if extra_errors = options.delete(:errors)
15
+ extra_errors.each do |key, value|
16
+ d_errors[key] = value
17
+ end
18
+ end
19
+
20
+ d_errors.each do |key, error|
21
+ d_keys = (keys.dup << key)
22
+
23
+ error = error.first
24
+
25
+ if error.is_a?(Hash)
26
+ d_options = options.dup
27
+ d_options[:keys] = d_keys
28
+ d_options[:override_errors] = d_errors[key].first
29
+
30
+ display_errors d_options, &block
31
+ elsif !block_given? || block.call(d_keys, error) == false
32
+ name = d_keys.each_with_index.map do |field, i|
33
+ i != 0 ? "[#{field}]" : field
34
+ end.join
35
+
36
+ if tmpl = options[:tmpl]
37
+ if client?
38
+ field_error_dom = DOM.new(`#{tmpl.dom}[0].outerHTML`)
39
+ else
40
+ field_error_dom = DOM.new(tmpl.dom.to_html)
41
+ end
42
+ else
43
+ field_error_dom = DOM.new('<span class="field-error"><span>')
44
+ end
45
+
46
+ field_error_dom.html _error_name(key, error)
47
+
48
+ field = dom.find("[name='#{name}']")
49
+ field.before field_error_dom.dom
50
+ end
51
+ end
52
+ end
53
+ alias_method :render_errors, :display_errors
54
+
55
+ def render_values dom = false, key = false, data = false
56
+ dom = _options[:dom] unless dom
57
+ key = _options[:key] if !key && _options.key?(:key)
58
+
59
+ dom.find('input, select, textarea') do |element|
60
+ name = element['name']
61
+ next if name.nil?
62
+ name = name.gsub(/\A#{key}/, '') if key
63
+ keys = name.gsub(/\A\[/, '').gsub(/[^a-z0-9_]/, '|').gsub(/\|\|/, '|').gsub(/\|$/, '').split('|')
64
+ value = false
65
+
66
+ keys.each do |k|
67
+ begin
68
+ value = value != false ? value.send(k) : send(k)
69
+ rescue
70
+ value = ''
71
+ end
72
+ end
73
+
74
+ case element.name
75
+ when 'select'
76
+ element.find('option') do |x|
77
+ x['selected'] = true if x['value'] == value.to_s
78
+ end
79
+ when 'input'
80
+ if %w(radio checkbox).include? element['type']
81
+ if element['value'] == value.to_s
82
+ element['checked'] = true
83
+ else
84
+ element.delete 'checked'
85
+ end
86
+ else
87
+ value = sprintf('%.2f', value) if value.is_a? BigDecimal
88
+ element['value'] = value.to_s
89
+ end
90
+ when 'textarea'
91
+ element.val value.to_s
92
+ end
93
+ end
94
+ end
95
+
96
+ def _error_name key, error
97
+ case error.to_s.to_sym
98
+ when :not_email
99
+ 'Email Isn\'t Valid.'
100
+ when :not_present
101
+ 'Required.'
102
+ when :not_equal
103
+ 'Password does not match.'
104
+ else
105
+ !error[/\s/] ? error.to_s.gsub(/_/, ' ').titleize : error
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -3,10 +3,10 @@ class Wedge
3
3
  class Uploader < Component
4
4
  name :uploader, :uploader_plugin
5
5
 
6
- on :compile do
6
+ on :compile do |for_client|
7
7
  settings = Wedge.config.settings[:uploader]
8
8
  store[:settings] = settings.select do |k, v|
9
- client? ? %w(aws_access_key_id bucket).include?(k) : true
9
+ for_client ? %i(aws_access_key_id bucket).include?(k) : true
10
10
  end if settings
11
11
  end
12
12
 
@@ -0,0 +1,104 @@
1
+ #--
2
+ # Most objects are cloneable, but not all. For example you can't dup +nil+:
3
+ #
4
+ # nil.dup # => TypeError: can't dup NilClass
5
+ #
6
+ # Classes may signal their instances are not duplicable removing +dup+/+clone+
7
+ # or raising exceptions from them. So, to dup an arbitrary object you normally
8
+ # use an optimistic approach and are ready to catch an exception, say:
9
+ #
10
+ # arbitrary_object.dup rescue object
11
+ #
12
+ # Rails dups objects in a few critical spots where they are not that arbitrary.
13
+ # That rescue is very expensive (like 40 times slower than a predicate), and it
14
+ # is often triggered.
15
+ #
16
+ # That's why we hardcode the following cases and check duplicable? instead of
17
+ # using that rescue idiom.
18
+ #++
19
+ class Object
20
+ # Can you safely dup this object?
21
+ #
22
+ # False for +nil+, +false+, +true+, symbol, number objects;
23
+ # true otherwise.
24
+ def duplicable?
25
+ true
26
+ end
27
+ end
28
+
29
+ # fix: this is a current hack, as of opal 0.8 you can't #dup/#clone procs
30
+ if RUBY_ENGINE == 'opal'
31
+ class Proc
32
+ def duplicable?
33
+ false
34
+ end
35
+ end
36
+ end
37
+
38
+ class NilClass
39
+ # +nil+ is not duplicable:
40
+ #
41
+ # nil.duplicable? # => false
42
+ # nil.dup # => TypeError: can't dup NilClass
43
+ def duplicable?
44
+ false
45
+ end
46
+ end
47
+
48
+ class FalseClass
49
+ # +false+ is not duplicable:
50
+ #
51
+ # false.duplicable? # => false
52
+ # false.dup # => TypeError: can't dup FalseClass
53
+ def duplicable?
54
+ false
55
+ end
56
+ end
57
+
58
+ class TrueClass
59
+ # +true+ is not duplicable:
60
+ #
61
+ # true.duplicable? # => false
62
+ # true.dup # => TypeError: can't dup TrueClass
63
+ def duplicable?
64
+ false
65
+ end
66
+ end
67
+
68
+ class Symbol
69
+ # Symbols are not duplicable:
70
+ #
71
+ # :my_symbol.duplicable? # => false
72
+ # :my_symbol.dup # => TypeError: can't dup Symbol
73
+ def duplicable?
74
+ false
75
+ end
76
+ end
77
+
78
+ class Numeric
79
+ # Numbers are not duplicable:
80
+ #
81
+ # 3.duplicable? # => false
82
+ # 3.dup # => TypeError: can't dup Fixnum
83
+ def duplicable?
84
+ false
85
+ end
86
+ end
87
+
88
+ defined?(::BigDecimal) or require 'bigdecimal' unless RUBY_ENGINE == 'opal'
89
+
90
+ class BigDecimal
91
+ def duplicable?
92
+ true
93
+ end
94
+ end
95
+
96
+ class Method
97
+ # Methods are not duplicable:
98
+ #
99
+ # method(:puts).duplicable? # => false
100
+ # method(:puts).dup # => TypeError: allocator undefined for Method
101
+ def duplicable?
102
+ false
103
+ end
104
+ end
@@ -1,3 +1,5 @@
1
+ require_relative 'duplicable'
2
+
1
3
  class Hash
2
4
  # add keys to hash
3
5
  def to_obj
@@ -103,3 +105,49 @@ class HashObject
103
105
  Wedge::IndifferentHash.new self.to_h.inject({}) {|copy, (key, value)| copy[key] = value.dup rescue value; copy}
104
106
  end
105
107
  end
108
+
109
+ class Object
110
+ # Returns a deep copy of object if it's duplicable. If it's
111
+ # not duplicable, returns +self+.
112
+ #
113
+ # object = Object.new
114
+ # dup = object.deep_dup
115
+ # dup.instance_variable_set(:@a, 1)
116
+ #
117
+ # object.instance_variable_defined?(:@a) # => false
118
+ # dup.instance_variable_defined?(:@a) # => true
119
+ def deep_dup
120
+ duplicable? ? dup : self
121
+ end
122
+ end
123
+
124
+ class Array
125
+ # Returns a deep copy of array.
126
+ #
127
+ # array = [1, [2, 3]]
128
+ # dup = array.deep_dup
129
+ # dup[1][2] = 4
130
+ #
131
+ # array[1][2] # => nil
132
+ # dup[1][2] # => 4
133
+ def deep_dup
134
+ map(&:deep_dup)
135
+ end
136
+ end
137
+
138
+ class Hash
139
+ # Returns a deep copy of hash.
140
+ #
141
+ # hash = { a: { b: 'b' } }
142
+ # dup = hash.deep_dup
143
+ # dup[:a][:c] = 'c'
144
+ #
145
+ # hash[:a][:c] # => nil
146
+ # dup[:a][:c] # => "c"
147
+ def deep_dup
148
+ each_with_object(dup) do |(key, value), hash|
149
+ hash.delete(key)
150
+ hash[key.deep_dup] = value.deep_dup
151
+ end
152
+ end
153
+ end
data/lib/wedge/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Wedge
2
- VERSION = '0.1.17'
2
+ VERSION = '0.1.18'
3
3
  end
@@ -1,6 +1,9 @@
1
1
  class Playground
2
2
  use Rack::Session::Cookie, secret: APP_SECRET
3
+ # gzips assets
4
+ use Rack::Deflater, include: %w{text/plain application/xml application/json application/javascript text/css text/json}
3
5
 
6
+ plugin :middleware
4
7
  plugin :environments
5
8
 
6
9
  configure :development do
@@ -13,17 +16,26 @@ class Playground
13
16
  BetterErrors.application_root = Dir.pwd
14
17
  end
15
18
 
16
- plugin :wedge, {
17
- scope: self,
18
- plugins: [:form],
19
- settings: {
20
- uploader: {
21
- aws_access_key_id: AWS_ACCESS_KEY_ID,
22
- aws_secret_access_key: AWS_SECRET_ACCESS_KEY,
23
- bucket: AWS_BUCKET
24
- }
19
+ plugin :csrf, skip_if: ->(_) { RACK_ENV == 'test' }
20
+ plugin :wedge do |c|
21
+ c.scope = Playground
22
+ c.debug = true
23
+ c.app_dir = RACK_ENV != 'test' ? 'app' : 'playground/app'
24
+ c.plugin :form
25
+ c.plugin :current_user, client_fields: %w'id first_name last_name is_admin' do
26
+ User.find(1)
27
+ end
28
+ # c.plugin_settings :uploader, {
29
+ # aws_access_key_id: AWS_ACCESS_KEY_ID,
30
+ # aws_secret_access_key: AWS_SECRET_ACCESS_KEY,
31
+ # bucket: AWS_BUCKET
32
+ # }
33
+ c.settings[:uploader] = {
34
+ aws_access_key_id: AWS_ACCESS_KEY_ID,
35
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY,
36
+ bucket: AWS_BUCKET
25
37
  }
26
- }
38
+ end
27
39
 
28
40
  # builder = Opal::Builder.new(:stubs=>['opal'])
29
41
  # builder.append_paths(APP_ROOT)
@@ -49,7 +61,7 @@ class Playground
49
61
  }
50
62
 
51
63
  route do |r|
52
- r.wedge_assets
64
+ # r.wedge_assets
53
65
  r.assets
54
66
 
55
67
  r.root do
@@ -59,5 +71,9 @@ class Playground
59
71
  r.on 'uploader' do
60
72
  wedge(:uploader).to_js :display
61
73
  end
74
+
75
+ r.on 'todo_list' do
76
+ wedge(:todo_list).to_js :display
77
+ end
62
78
  end
63
79
  end
@@ -0,0 +1,11 @@
1
+ class Playground
2
+ class Abilities < Wedge::Plugins::AbilityList
3
+ name :ability_list
4
+
5
+ def initialize user
6
+ if user.admin?
7
+ can :view, :admin
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class Playground
2
+ class CurrentUserComponent < Wedge::Plugins::CurrentUser
3
+ name :current_user
4
+
5
+ attr_reader :id, :is_admin, :secret_key
6
+ attr_accessor :first_name, :last_name
7
+
8
+ def admin?
9
+ is_admin
10
+ end
11
+ end
12
+ end
@@ -29,9 +29,14 @@ class Playground
29
29
  def display options = {}, &block
30
30
  return unless server?
31
31
 
32
+ begin; dom.find('head').add_child csrf_metatag; rescue; end
32
33
  body_dom = dom.find('body')
33
34
  body_dom << block.call if block_given?
34
35
 
36
+ if body_class = options[:body_class]
37
+ body_dom.add_class body_class
38
+ end
39
+
35
40
  dom
36
41
  end
37
42
  end
@@ -0,0 +1,24 @@
1
+ require_relative '../forms/todo_list_add'
2
+
3
+ class Playground
4
+ class TodoListComponent < Wedge::Component
5
+ name :todo_list
6
+ html 'public/todo_list.html'
7
+
8
+ def display
9
+ wedge(:layout).display(body_class: 'todo_list') { dom } if server?
10
+ end
11
+
12
+ on :submit, '#add-form', key: :todo, form: :todo_list_add do |form, el|
13
+ button = el.find('button[type="submit"]')
14
+ button.prop("disabled", true)
15
+ if form.valid?
16
+ puts 'valid'
17
+ else
18
+ form.display_errors
19
+ button.prop("disabled", false)
20
+ puts 'errors'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -17,3 +17,6 @@ require 'app'
17
17
 
18
18
  Dir["#{APP_ROOT}/forms/*.rb"].sort.each { |file| require file }
19
19
  Dir["#{APP_ROOT}/components/*.rb"].sort.each { |file| require file }
20
+ Dir["#{APP_ROOT}/models/*.rb"].sort.each { |file| require file }
21
+
22
+ require './spec/spec_helper' if RACK_ENV == 'test'
@@ -0,0 +1,9 @@
1
+ class TodoListAddForm < Wedge::Plugins::Form
2
+ name :todo_list_add
3
+
4
+ attr_accessor :description
5
+
6
+ def validate
7
+ assert_present :description
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class Playground
2
+ class User
3
+
4
+ end
5
+ end