express_templates 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/core_extensions/string.rb +25 -0
  3. data/lib/express_templates/components/capabilities/resourceful.rb +135 -0
  4. data/lib/express_templates/components/forms/express_form.rb +2 -15
  5. data/lib/express_templates/components/forms/form_component.rb +2 -6
  6. data/lib/express_templates/components/forms/form_support.rb +13 -0
  7. data/lib/express_templates/components/forms/option_support.rb +19 -5
  8. data/lib/express_templates/components/forms/select.rb +47 -9
  9. data/lib/express_templates/components/forms/select_collection.rb +57 -0
  10. data/lib/express_templates/components/forms.rb +3 -1
  11. data/lib/express_templates/components/tree_for.rb +9 -5
  12. data/lib/express_templates/version.rb +1 -1
  13. data/lib/express_templates.rb +1 -0
  14. data/test/components/capabilities/resourceful_test.rb +63 -0
  15. data/test/components/forms/express_form_test.rb +9 -9
  16. data/test/components/forms/select_test.rb +50 -3
  17. data/test/core_extensions/string_test.rb +20 -0
  18. data/test/dummy/log/test.log +9268 -63499
  19. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/-1ax0k6FO5drSUN6jbogg4G0JliUHLffvQUvzSePKxA.cache +1 -0
  20. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/28LzLLDYjhr3jmu0GxjZ-ms5Bol6JilDRXpg8Zgbjqs.cache +1 -0
  21. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5AeGDyXQbv_BTj3PD4MJpNnGVwUxLsA8H1VcwB69_wE.cache +0 -0
  22. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/B0RgtiEmqwrCQuw4AnDa3fdENtJeBtO_TqtGJuWOeNs.cache +3 -0
  23. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/D-tMNp19G2zWOPPhnQRUm4K8DPa8SpKPfGALkkofTeE.cache +0 -0
  24. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Pd5YOD1DAL7QtTnwETZYBCabg5DkCFgbjt4iuBOcSoY.cache +1 -0
  25. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/bSfZQxeyghTF4WIVnzGavxlg9afmSNuqcW6bA1Bm1OA.cache +0 -0
  26. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fvD_ZNFRzd8Sc4PoTjyHPnkg4f7WMietFunnKqNjlvc.cache +2 -0
  27. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/hKbgrf5CbMO8pe9fCHc-rI5mp1ejAhivBfvfDxBNhQA.cache +0 -0
  28. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/kpvKX5UlhhoLJv-faeq7Ibv2KQh4ROjTiarh13gHuWI.cache +2 -0
  29. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/lfyrNtbNtwuTXAWlmPCKTS-D3FHoPTY6h53wnUN36-A.cache +0 -0
  30. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/lyDRhWNhfDw_YCCSbxQw_iOIV3eTfeAoX6mTREuVZSA.cache +3 -0
  31. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/p17lC0HAHCtk1ds_NHl9xhEyMtRjfQInw1c6fmFWguc.cache +0 -0
  32. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/qzU7DVwQZ7z6i6pYUpssYsAj0y33GN83B4O1bLvkW_4.cache +1 -0
  33. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/r56eI1z7iFKeySym_9zw5hVOPjb0d6IQPn5pAYTKk04.cache +2 -0
  34. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/rGWvoeLyiyqb813IXgfDpDxks23JQoLLZOa69bzKPE8.cache +1 -0
  35. metadata +42 -14
  36. data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  37. data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  38. data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  39. data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  40. data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  41. data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 30791598c725b41c362d6f436e51342db19abea2
4
- data.tar.gz: 139fc021df9d57161f27240a020826f203aebc40
3
+ metadata.gz: 7e3c4b0da15f9c3a8e15afd1cd406974c6a77830
4
+ data.tar.gz: 4fcaadfa00a739490b71b7a9539778aa3a7019e8
5
5
  SHA512:
6
- metadata.gz: 4889d57691fbb9a2f787381e42f89bcba50dd084381721003520e2aed39a11514befe3899587ffcab4192f7f2e333f39277681c30ee9c7cdd998c19dea4913d4
7
- data.tar.gz: 6d4623073cf1f498a4d542637f8a54331cfe7fda2088e33cf9cf05907835875175751a7a19e71adc9965f18f604b5cd450e753d6b4e2824fe5e810bdcea46717
6
+ metadata.gz: 4ad45dd634f82597ad578c21047556a4770ad76f05b7b92e344fbbde27993dc69a7ff1d53dd3c0c116e9dadc0f444633ea6dc325cf1a7cbcb596179946bea615
7
+ data.tar.gz: 1a67f14a59f8eac2b61a840376c0ff2ab1607a2e41533c6fa1543c5caa1ce7811a3d2d0b7b4ca3a66b745d8d38e2cfd99efafbf94d78a056284b187b163ea72b
@@ -0,0 +1,25 @@
1
+ # We use Hash#inspect in ExpressTemplates::Markup::Wrapper to reproduce arguments
2
+ # to helpers in the Rails view.
3
+ #
4
+ # Hash#inspect calls #inspect on values and keys. This allows us to
5
+ # place the resulting string into the view code with a simple substitution
6
+ # or concatenation.
7
+ #
8
+ # In special cases, however, we might want the argument or one of its keys
9
+ # or values to be the result of evaluating of a ruby expression in the view
10
+ # that does not itself return a String. The result of #inspect
11
+ # is normally a quoted and escaped string which would evaluate to a string
12
+ # in the view. What we want is a simple string of code. Here we provide
13
+ # a method that overrides #inspect in the strings eigenclass to strip off
14
+ # enclosing quotes or unwanted escapes. It shouldn't bother anybody and
15
+ # it keeps us from doing messy things elsewhere for now.
16
+ class String
17
+ def to_view_code
18
+ class << self
19
+ def inspect
20
+ super.gsub(/^"(.*)"$/,'\1')
21
+ end
22
+ end
23
+ return self
24
+ end
25
+ end
@@ -0,0 +1,135 @@
1
+ module ExpressTemplates
2
+ module Components
3
+ module Capabilities
4
+
5
+ module Resourceful
6
+ def namespace
7
+ @config[:namespace] || infer_namespace
8
+ end
9
+
10
+ def path_prefix
11
+ @config[:path_prefix] || infer_path_prefix
12
+ end
13
+
14
+ def resource_class
15
+ resource_class = @config[:resource_class] || _namespaced_resource_class
16
+ resource_class.constantize
17
+ end
18
+
19
+ private
20
+
21
+ def _namespaced_resource_class
22
+ if namespace
23
+ "#{namespace}/#{resource_name}".classify
24
+ else
25
+ resource_name.classify
26
+ end
27
+ end
28
+
29
+ def infer_namespace
30
+ expander = @args.last
31
+ if expander.try(:template)
32
+ path_parts = expander.template.virtual_path.split('/')
33
+
34
+ case
35
+ when path_parts.size == 4
36
+ path_parts.first
37
+ when path_parts.size == 3
38
+ mod = path_parts.first.classify.constantize
39
+ if mod.const_defined?(:Engine)
40
+ path_parts.first
41
+ else
42
+ nil
43
+ end
44
+ else
45
+ nil
46
+ end
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ def infer_path_prefix
53
+ expander = @args.last
54
+ if expander.try(:template)
55
+ path_parts = expander.template.virtual_path.split('/')
56
+
57
+ case
58
+ when path_parts.size == 4
59
+ path_parts[1]
60
+ when path_parts.size == 3
61
+ mod = path_parts.first.classify.constantize
62
+ if mod.const_defined?(:Engine)
63
+ nil
64
+ else
65
+ path_parts.first
66
+ end
67
+ else
68
+ nil
69
+ end
70
+ else
71
+ nil
72
+ end
73
+ end
74
+
75
+ # TODO: this can now be inferred from the template.virtual_path
76
+ # if not supplied...
77
+ def resource_name
78
+ @config[:id].to_s.singularize
79
+ end
80
+
81
+ def collection_member_name
82
+ resource_name
83
+ end
84
+
85
+ def collection_name
86
+ collection_member_name.pluralize
87
+ end
88
+
89
+ def collection_var
90
+ "@#{collection_name}".to_sym
91
+ end
92
+
93
+ def collection
94
+ @config[:collection] || collection_var
95
+ end
96
+
97
+ def collection_path
98
+ if @config[:collection_path]
99
+ @config[:collection_path]
100
+ else
101
+ "#{collection_name_with_prefix}_path"
102
+ end
103
+ end
104
+
105
+ def collection_name_with_prefix
106
+ if path_prefix
107
+ "#{path_prefix}_#{collection_name}"
108
+ else
109
+ collection_name
110
+ end
111
+ end
112
+
113
+ def resource_path(ivar=false)
114
+ if @config[:resource_path]
115
+ @config[:resource_path]
116
+ else
117
+ "#{resource_name_with_path_prefix}_path(#{ivar ? '@' : ''}#{resource_name})"
118
+ end
119
+ end
120
+
121
+ def resource_name_with_path_prefix
122
+ if path_prefix
123
+ "#{path_prefix}_#{resource_name}"
124
+ else
125
+ resource_name
126
+ end
127
+ end
128
+
129
+ def attributes
130
+ resource_class.columns
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -4,6 +4,8 @@ module ExpressTemplates
4
4
  class ExpressForm < Base
5
5
  include Capabilities::Configurable
6
6
  include Capabilities::Parenting
7
+ include Capabilities::Resourceful
8
+ include Forms::FormSupport
7
9
 
8
10
  emits -> {
9
11
  form( form_args ) {
@@ -20,16 +22,6 @@ module ExpressTemplates
20
22
  @config[:method]
21
23
  end
22
24
 
23
- def form_action
24
- if _modifying_resource?
25
- "{{#{resource_name_for_path}_path(@#{resource_name})}}"
26
- else # posting a new to a collection
27
- # We also have to take in to account singular resources
28
- # e.g. resource :config -> will throw an unknown method error of configs_path
29
- "{{#{resource_name_for_path.pluralize}_path}}"
30
- end
31
- end
32
-
33
25
 
34
26
  def form_args
35
27
  # there are no put/patch emthods in HTML5, so we have to enforce post
@@ -52,11 +44,6 @@ module ExpressTemplates
52
44
  (@config[:resource_name] || @config[:id]).to_s
53
45
  end
54
46
 
55
- def namespace
56
- @config[:namespace]
57
- end
58
-
59
-
60
47
  private
61
48
 
62
49
  def _modifying_resource?
@@ -20,11 +20,7 @@ module ExpressTemplates
20
20
  end
21
21
 
22
22
  def resource_class
23
- if namespace = parent_form.namespace
24
- "#{namespace}/#{resource_name}".classify
25
- else
26
- resource_name.classify
27
- end
23
+ parent_form.resource_class
28
24
  end
29
25
 
30
26
  # Return the name attribute for the lable
@@ -34,7 +30,7 @@ module ExpressTemplates
34
30
 
35
31
  # Return the text content for the label
36
32
  def label_text
37
- @options[:label] || field_name.titleize
33
+ @config[:label] || field_name.titleize
38
34
  end
39
35
 
40
36
  # Return the field_name as a string. This taken from the first argument
@@ -0,0 +1,13 @@
1
+ module ExpressTemplates
2
+ module Components
3
+ module Forms
4
+ module FormSupport
5
+
6
+ def form_action
7
+ @config[:action] || "{{@#{resource_name}.try(:persisted?) ? #{resource_path(ivar: true)} : #{collection_path}}}"
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -5,12 +5,18 @@ module ExpressTemplates
5
5
  # on the field and an means of loading the collection for supplying
6
6
  # options to the user.
7
7
  module OptionSupport
8
+
9
+ def has_many_through_association
10
+ reflection = resource_class.reflect_on_association(field_name.to_sym)
11
+ return reflection if reflection && reflection.macro.eql?(:has_many) && reflection.options.keys.include?(:through)
12
+ end
13
+
8
14
  # Reflect on any association and return it if the association type
9
15
  # is :belongs_to. Returns false if the association is not :belongs_to.
10
16
  # Returns nil if there was a problem reflecting.
11
17
  def belongs_to_association
12
18
  # assumes the belongs_to association uses <name>_id
13
- reflection = resource_class.constantize.reflect_on_association(field_name.gsub(/_id$/, '').to_sym)
19
+ reflection = resource_class.reflect_on_association(field_name.gsub(/_id$/, '').to_sym)
14
20
  if reflection && reflection.macro.eql?(:belongs_to)
15
21
  return reflection
16
22
  end
@@ -19,9 +25,13 @@ module ExpressTemplates
19
25
  # Provide ActiveRecord code to load the associated collection as
20
26
  # options for display.
21
27
  def related_collection
22
- reflection = belongs_to_association
28
+ reflection = belongs_to_association || has_many_through_association
23
29
  if reflection && !reflection.polymorphic?
24
- "#{reflection.klass}.all.select(:#{option_value_method}, :#{option_name_method}).order(:#{option_name_method})"
30
+ if cols.detect {|column| column.name.eql?('name') }
31
+ "#{reflection.klass}.all.select(:#{option_value_method}, :#{option_name_method}).order(:#{option_name_method})"
32
+ else
33
+ "#{reflection.klass}.all.sort_by(&:#{option_name_method})"
34
+ end
25
35
  end
26
36
  end
27
37
 
@@ -31,10 +41,14 @@ module ExpressTemplates
31
41
  :id
32
42
  end
33
43
 
44
+ def cols
45
+ @cols ||= (belongs_to_association||has_many_through_association).klass.columns
46
+ end
47
+
34
48
  def option_name_method
35
- cols = belongs_to_association.klass.columns
36
49
  @option_name_method ||=
37
- if cols.detect {|column| column.name.eql?('name') }
50
+ if cols.detect {|column| column.name.eql?('name') } ||
51
+ resource_class.instance_methods.include?(:name)
38
52
  :name
39
53
  else
40
54
  if string_col = cols.detect {|column| column.type.eql?(:string) }
@@ -21,15 +21,26 @@ module ExpressTemplates
21
21
  emits -> {
22
22
  div(class: field_wrapper_class) {
23
23
  label_tag(label_name, label_text)
24
- select_tag(field_name_attribute, select_options, field_options)
24
+ select_tag(*select_tag_args)
25
25
  }
26
26
  }
27
27
 
28
+ def select_tag_args
29
+ args = [field_name_attribute, select_options, field_options]
30
+ args << html_options unless html_options.nil? or html_options.empty?
31
+ args
32
+ end
33
+
28
34
  # Returns the options which will be supplied to the select_tag helper.
29
35
  def select_options
30
- options_specified = [Array, Hash].include?(@args.second.class) && @args.size > 2
36
+ options_specified = [Array, Hash, Proc].include?(@args.second.class) && @args.size > 2
31
37
  if options_specified
32
- options = @args.second
38
+ if @args.second.respond_to?(:source) # can be a proc
39
+ options = "#{@args.second.source}.call()"
40
+ else
41
+ options = @args.second
42
+ end
43
+
33
44
  else
34
45
  options = "@#{resource_var}.class.distinct(:#{field_name}).pluck(:#{field_name})"
35
46
  end
@@ -40,6 +51,8 @@ module ExpressTemplates
40
51
  else
41
52
  "{{options_from_collection_for_select(#{related_collection}, :id, :#{option_name_method}, @#{resource_name}.#{field_name})}}"
42
53
  end
54
+ elsif has_many_through_association
55
+ "{{options_from_collection_for_select(#{related_collection}, :id, :#{option_name_method}, @#{resource_name}.#{field_name}.map(&:id))}}"
43
56
  else
44
57
  if selection = field_options.delete(:selected)
45
58
  "{{options_for_select(#{options}, \"#{selection}\")}}"
@@ -49,18 +62,43 @@ module ExpressTemplates
49
62
  end
50
63
  end
51
64
 
65
+ def field_name_attribute
66
+ if has_many_through_association
67
+ "#{resource_name.singularize}[#{field_name.singularize}_ids]"
68
+ else
69
+ super
70
+ end
71
+ end
72
+
52
73
  def field_options
53
74
  # If field_otions is omitted the Expander will be
54
75
  # in last or 3rd position and we don't want that
55
76
  defaults = {include_blank: true}
56
- field_options = if @args.size > 3 && @args[2].is_a?(Hash)
57
- @args[2]
58
- else
59
- {}
60
- end
61
- defaults.merge(field_options)
77
+ defaults.merge(supplied_field_options.reject {|k,v| k.eql?(:select2)})
62
78
  end
63
79
 
80
+ def html_options
81
+ supplied_html_options
82
+ end
83
+
84
+ protected
85
+
86
+ def supplied_field_options
87
+ if @args.size > 3 && @args[2].is_a?(Hash)
88
+ @args[2]
89
+ else
90
+ {}
91
+ end
92
+ end
93
+
94
+ def supplied_html_options
95
+ if @args.size > 4 && @args[3].is_a?(Hash)
96
+ @args[3]
97
+ else
98
+ {}
99
+ end
100
+ end
101
+
64
102
  end
65
103
  end
66
104
  end
@@ -0,0 +1,57 @@
1
+ module ExpressTemplates
2
+ module Components
3
+ module Forms
4
+ # Provides a form Select component based on the Rails *select_tag* helper.
5
+ # Parameters:
6
+ # field_name, select_options, helper_options
7
+ #
8
+ # Select options may be specified as an Array or Hash which will be
9
+ # supplied to the *options_for_select* helper.
10
+ #
11
+ class SelectCollection < Select
12
+
13
+ emits -> {
14
+ div(class: field_wrapper_class) {
15
+ label_tag(label_name, label_text)
16
+
17
+ # need this because the collection_select helper does not provide
18
+ # the hidden_field_tag trick (see rails api docs for select)
19
+ hidden_field_tag(multi_field_name, '')
20
+
21
+ collection_select(*collection_select_tag_args)
22
+ }
23
+ }
24
+
25
+ def collection_select_tag_args
26
+ [ resource_name,
27
+ multi_field_name,
28
+ select_options, :id, :name,
29
+ field_options,
30
+ html_options ]
31
+ end
32
+
33
+ def field_options
34
+ selected_options_ruby = "@#{resource_name}.#{multi_field_name}".to_view_code
35
+ super.merge(include_blank: false, selected: selected_options_ruby)
36
+ end
37
+
38
+ def html_options
39
+ (super||{}).merge(multiple: true)
40
+ end
41
+
42
+ def multi_field_name
43
+ if has_many_through_association
44
+ "#{field_name.singularize}_ids"
45
+ else
46
+ raise "Only use select_collection for has_many :through. #{field_name} is not has_many :through"
47
+ end
48
+ end
49
+
50
+
51
+ def select_options
52
+ "{{#{related_collection}}}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -5,11 +5,13 @@ module ExpressTemplates
5
5
  end
6
6
  end
7
7
 
8
+ require 'express_templates/components/forms/form_support'
8
9
  require 'express_templates/components/forms/express_form'
9
10
  require 'express_templates/components/forms/form_component'
10
11
  require 'express_templates/components/forms/option_support'
11
12
  require 'express_templates/components/forms/submit'
12
13
  require 'express_templates/components/forms/select'
14
+ require 'express_templates/components/forms/select_collection'
13
15
  require 'express_templates/components/forms/radio'
14
16
  require 'express_templates/components/forms/checkbox'
15
- require 'express_templates/components/forms/basic_fields'
17
+ require 'express_templates/components/forms/basic_fields'
@@ -11,9 +11,9 @@ module ExpressTemplates
11
11
  # Example:
12
12
  #
13
13
  # ```ruby
14
- # tree_for(:roles) do |role|
15
- # role.name
16
- # end
14
+ # tree_for(:roles) {
15
+ # "{{role.name}}"
16
+ # }
17
17
  # ```
18
18
  #
19
19
  # If the view has an @roles variable with a Role having children,
@@ -59,12 +59,16 @@ module ExpressTemplates
59
59
  end
60
60
 
61
61
  def compile
62
- collection = _variablize(@options[:id])
62
+ collection = if @options[:collection]
63
+ "#{@options[:collection].source}.call()"
64
+ else
65
+ _variablize(@options[:id])
66
+ end
63
67
  member = @options[:id].to_s.singularize
64
68
  return 'ExpressTemplates::Components::TreeFor.render_in(self) {
65
69
  node_renderer = '+node_renderer.gsub(/node/, member)+'
66
70
  ExpressTemplates::Indenter.for(:tree) do |ws, wsnl|
67
- "#{ws}<ul id=\"roles\" class=\"roles tree\">" +
71
+ "#{ws}<ul id=\"'+@options[:id]+'\" class=\"'+@options[:id]+' tree\">" +
68
72
  '+collection+'.map do |'+member+'|
69
73
  node_renderer.call('+member+', node_renderer)
70
74
  end.join +
@@ -1,3 +1,3 @@
1
1
  module ExpressTemplates
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  module ExpressTemplates
2
2
  require 'core_extensions/proc'
3
+ require 'core_extensions/string'
3
4
  require 'express_templates/indenter'
4
5
  require 'express_templates/macro'
5
6
  require 'express_templates/markup'
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+
3
+ module AdminModule
4
+ module Engine
5
+ end
6
+ class SmartThing
7
+ include ExpressTemplates::Components::Capabilities::Resourceful
8
+
9
+ attr_accessor :virtual_path
10
+
11
+ def initialize(virtual_path, config = {})
12
+ @virtual_path = virtual_path
13
+ @config = config
14
+ @args = [self]
15
+ end
16
+
17
+ def template
18
+ self
19
+ end
20
+ end
21
+ end
22
+
23
+ module Admin; end
24
+
25
+ class FooBar; end
26
+
27
+ class Something; end
28
+
29
+ module ExpressTemplates
30
+
31
+ class ResourcefulTest < ActiveSupport::TestCase
32
+ test 'infers namespace and path prefix within an engine and scope' do
33
+ smart_thing = AdminModule::SmartThing.new('admin_module/admin/something/index')
34
+ assert_equal 'admin_module', smart_thing.namespace
35
+ assert_equal 'admin', smart_thing.path_prefix
36
+ end
37
+
38
+ test 'infers a namespace and no prefix within an engine' do
39
+ # if defined? ExpressFoo::Engine
40
+ smart_thing = AdminModule::SmartThing.new('admin_module/something/index')
41
+ assert_equal 'admin_module', smart_thing.namespace
42
+ assert_equal nil, smart_thing.path_prefix
43
+ end
44
+
45
+ test 'no namespace, infers prefix within a scope within an app' do
46
+ # else of case above
47
+ smart_thing = AdminModule::SmartThing.new('admin/something/index')
48
+ assert_equal nil, smart_thing.namespace
49
+ assert_equal 'admin', smart_thing.path_prefix
50
+ end
51
+
52
+ test 'no namespace, no prefix within an app' do
53
+ smart_thing = AdminModule::SmartThing.new('somethings/index')
54
+ assert_equal nil, smart_thing.namespace
55
+ assert_equal nil, smart_thing.path_prefix
56
+ end
57
+
58
+ test "#resource_class returns resource_class option if specified" do
59
+ assert_equal FooBar, AdminModule::SmartThing.new('somethings/index', resource_class: 'FooBar').resource_class
60
+ assert_equal Something, AdminModule::SmartThing.new('somethings/index', id: :something).resource_class
61
+ end
62
+ end
63
+ end
@@ -72,16 +72,16 @@ class ExpressFormTest < ActiveSupport::TestCase
72
72
  end
73
73
 
74
74
  test "#form_action uses url helpers" do
75
- assert_equal "{{foos_path}}", express_form.new(:foo).form_action
75
+ assert_equal "{{@foo.try(:persisted?) ? foo_path(@foo) : foos_path}}", express_form.new(:foo).form_action
76
76
  end
77
77
 
78
78
  test "#form_action uses correct path helper for update/patch" do
79
- assert_equal "{{foo_path(@foo)}}", express_form.new(:foo, method: :put).form_action
79
+ assert_equal "{{@foo.try(:persisted?) ? foo_path(@foo) : foos_path}}", express_form.new(:foo, method: :put).form_action
80
80
  end
81
81
 
82
82
  test "simplest_form uses form_action for the action" do
83
83
  form_open_tag = compile_simplest_form.match(/<form[^>]*>/)[0]
84
- assert_match 'action=\"#{resources_path}\"', form_open_tag
84
+ assert_match 'action=\"#{@resource.try(:persisted?) ? resource_path(@resource) : resources_path}\"', form_open_tag
85
85
  end
86
86
 
87
87
  test "express_form default method is POST" do
@@ -99,10 +99,10 @@ class ExpressFormTest < ActiveSupport::TestCase
99
99
  assert_equal 'foo', expanded_nodes.first.resource_name
100
100
  end
101
101
 
102
- test "express_form has a namespace option with nil default" do
103
- form = ExpressTemplates::Components::Forms::ExpressForm
104
- assert_nil form.new(:person).namespace
105
- assert_equal 'express_engine', form.new(:person, namespace: 'express_engine').namespace
106
- end
102
+ # test "express_form has a namespace option with nil default" do
103
+ # form = ExpressTemplates::Components::Forms::ExpressForm
104
+ # assert_nil form.new(:person).namespace
105
+ # assert_equal 'express_engine', form.new(:person, namespace: 'express_engine').namespace
106
+ # end
107
107
 
108
- end
108
+ end
@@ -52,16 +52,31 @@ class SelectTest < ActiveSupport::TestCase
52
52
  [OpenStruct.new(name: 'id'), OpenStruct.new(name: 'name')]
53
53
  end
54
54
  end
55
+ class ::Tagging
56
+ def self.columns
57
+ [OpenStruct.new(name: 'id'), OpenStruct.new(name: 'name')]
58
+ end
59
+ end
55
60
  class ::Person
56
61
  def self.reflect_on_association(name)
57
62
  if name.eql? :gender
58
- dummy_association = Object.new
59
- class << dummy_association
63
+ dummy_belongs_to_association = Object.new
64
+ class << dummy_belongs_to_association
60
65
  def macro ; :belongs_to ; end
61
66
  def klass ; ::Gender ; end
62
67
  def polymorphic? ; false ; end
63
68
  end
64
- return dummy_association
69
+ return dummy_belongs_to_association
70
+ end
71
+ if name.eql? :taggings
72
+ dummy_has_many_through_association = Object.new
73
+ class << dummy_has_many_through_association
74
+ def macro ; :has_many ; end
75
+ def klass ; ::Tagging ; end
76
+ def options ; {:through => :peron_tags} ; end
77
+ def polymorphic? ; false ; end
78
+ end
79
+ return dummy_has_many_through_association
65
80
  end
66
81
  end
67
82
  end
@@ -96,4 +111,36 @@ class SelectTest < ActiveSupport::TestCase
96
111
  assert_no_match 'include_blank: true', ExpressTemplates.compile(&fragment)
97
112
  end
98
113
 
114
+ test "select multiple: true if passed multiple true" do
115
+ fragment = -> {
116
+ express_form(:person) {
117
+ select :taggings, nil, include_blank: false, multiple: true
118
+ }
119
+ }
120
+ assert_match 'multiple: true', ExpressTemplates.compile(&fragment)
121
+ end
122
+
123
+ test "select multiple gets options from associated has_many_through collection" do
124
+ fragment = -> {
125
+ express_form(:person) {
126
+ select :taggings, nil, include_blank: false, multiple: true
127
+ }
128
+ }
129
+ assert_match 'tagging_ids', ExpressTemplates.compile(&fragment)
130
+ assert_match 'options_from_collection_for_select(Tagging.all.select(:id, :name).order(:name), :id, :name, @person.taggings.map(&:id))',
131
+ ExpressTemplates.compile(&fragment)
132
+ end
133
+
134
+ test "select_collection uses collection_select" do
135
+ fragment = -> {
136
+ express_form(:person) {
137
+ select_collection :taggings
138
+ }
139
+ }
140
+ assert_match 'tagging_ids', ExpressTemplates.compile(&fragment)
141
+ assert_match 'collection_select("person", "tagging_ids", Tagging.all.select(:id, :name).order(:name), :id, :name, {:include_blank=>false, :selected=>@person.tagging_ids}, multiple: true)',
142
+ ExpressTemplates.compile(&fragment)
143
+ end
144
+
145
+
99
146
  end