express_templates 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -41
  3. data/lib/arbre/patches.rb +50 -0
  4. data/lib/core_extensions/proc.rb +1 -0
  5. data/lib/express_templates/compiler.rb +2 -7
  6. data/lib/express_templates/components/base.rb +33 -37
  7. data/lib/express_templates/components/capabilities/resourceful.rb +30 -18
  8. data/lib/express_templates/components/configurable.rb +41 -0
  9. data/lib/express_templates/components/form_rails_support.rb +5 -6
  10. data/lib/express_templates/components/forms/basic_fields.rb +3 -6
  11. data/lib/express_templates/components/forms/checkbox.rb +1 -1
  12. data/lib/express_templates/components/forms/express_form.rb +15 -25
  13. data/lib/express_templates/components/forms/form_component.rb +20 -11
  14. data/lib/express_templates/components/forms/option_support.rb +2 -2
  15. data/lib/express_templates/components/forms/radio.rb +7 -8
  16. data/lib/express_templates/components/forms/select.rb +61 -37
  17. data/lib/express_templates/components/forms/select_collection.rb +2 -8
  18. data/lib/express_templates/components/forms/submit.rb +7 -6
  19. data/lib/express_templates/components/forms.rb +0 -1
  20. data/lib/express_templates/components/tree_for.rb +26 -42
  21. data/lib/express_templates/components.rb +1 -9
  22. data/lib/express_templates/version.rb +1 -1
  23. data/lib/express_templates.rb +2 -3
  24. data/test/components/base_test.rb +17 -15
  25. data/test/components/capabilities/resourceful_test.rb +3 -3
  26. data/test/components/configurable_test.rb +27 -21
  27. data/test/components/forms/basic_fields_test.rb +57 -17
  28. data/test/components/forms/checkbox_test.rb +16 -22
  29. data/test/components/forms/express_form_test.rb +23 -76
  30. data/test/components/forms/radio_test.rb +31 -27
  31. data/test/components/forms/select_test.rb +46 -71
  32. data/test/components/forms/submit_test.rb +10 -5
  33. data/test/components/tree_for_test.rb +24 -52
  34. data/test/dummy/app/views/hello/show.html.et +4 -3
  35. data/test/dummy/app/views/layouts/application.html.et +1 -1
  36. data/test/dummy/log/test.log +4794 -0
  37. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/-cDLO4NJHMndDHchOLz8KLD7QBc68WtaAbYxK2r6GsU.cache +0 -0
  38. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/0t68EIwZ96sAqQSxFka9MQyIk4viw8ZIoREMCGiJRx0.cache +0 -0
  39. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/2zt1IbQCnmzGyeZS_I4sYQzrgneSCKIJBRxcffVHlWY.cache +1 -0
  40. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/EDVlXrcn_wEfaZ5nc_4QJBT7lPiIBcX96jBo7PBz-vc.cache +1 -0
  41. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Eso3tkb79hXQ1XdQgjbV03KyQwSeZFAHxVHImsjQ-HQ.cache +2 -0
  42. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/I8LhheC1OlOyvp_qY8kWpqKcZFiqv_BO-l5bExvDEi0.cache +1 -0
  43. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Kf4VrP5sW-qzziYSN-m7p4nETjLiEwwwRfwUOm7rOr0.cache +0 -0
  44. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QJ0Z8hROMfWpY6f5Chb7GSuDHE4gpabKVQTr9BCZe9s.cache +1 -0
  45. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/T1pSAx767vY7X1UDN0vdF7YGEkI5wMSVUKopsdvp7kI.cache +1 -0
  46. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VlSPFPDK05c7ImadRiRVKzsaa6e15RwX77QR3NYabME.cache +0 -0
  47. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Y7_BbgB9jgJIWYjDCsASySd26DTfPADAu_3DDnLlFog.cache +0 -0
  48. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/g2xQygPqA5kMmp5L3wVGWaUIhdVsxFmOel9FF6M0Fuw.cache +0 -0
  49. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/kaif59owjUr3HBharCH5GUxU6KoW_zXD9a9JiTjIYPY.cache +1 -0
  50. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/p1cwnBd8RQBm9x5HzDmiiU7RhvnxhPX8VTfi0tTElJY.cache +3 -0
  51. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/qT6_0ti_v6fAjS3wETXqvTkr6W0LP4PB942uLYQzWK8.cache +3 -0
  52. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/y8T65xpx0s3RgT_YiqWEEXIaBsgK4woCNSuZ1zjQZBk.cache +2 -0
  53. data/test/express_templates_test.rb +5 -1
  54. data/test/handler_test.rb +19 -17
  55. data/test/performance_test.rb +11 -7
  56. data/test/test_helper.rb +162 -1
  57. metadata +50 -53
  58. data/lib/express_templates/components/capabilities/adoptable.rb +0 -20
  59. data/lib/express_templates/components/capabilities/building.rb +0 -14
  60. data/lib/express_templates/components/capabilities/conditionality.rb +0 -54
  61. data/lib/express_templates/components/capabilities/configurable.rb +0 -90
  62. data/lib/express_templates/components/capabilities/iterating.rb +0 -75
  63. data/lib/express_templates/components/capabilities/parenting.rb +0 -72
  64. data/lib/express_templates/components/capabilities/rendering.rb +0 -30
  65. data/lib/express_templates/components/capabilities/templating.rb +0 -198
  66. data/lib/express_templates/components/capabilities/wrapping.rb +0 -84
  67. data/lib/express_templates/components/column.rb +0 -13
  68. data/lib/express_templates/components/container.rb +0 -7
  69. data/lib/express_templates/components/content_for.rb +0 -42
  70. data/lib/express_templates/components/for_each.rb +0 -30
  71. data/lib/express_templates/components/forms/form_support.rb +0 -13
  72. data/lib/express_templates/components/null_wrap.rb +0 -41
  73. data/lib/express_templates/components/row.rb +0 -28
  74. data/lib/express_templates/components/table_for.rb +0 -163
  75. data/lib/express_templates/components/unless_block.rb +0 -40
  76. data/lib/express_templates/expander.rb +0 -140
  77. data/lib/express_templates/macro.rb +0 -45
  78. data/lib/express_templates/markup/html_tag.rb +0 -62
  79. data/lib/express_templates/markup/tag.rb +0 -150
  80. data/lib/express_templates/markup/wrapper.rb +0 -94
  81. data/lib/express_templates/markup/yielder.rb +0 -21
  82. data/lib/express_templates/markup.rb +0 -9
  83. data/test/components/column_test.rb +0 -11
  84. data/test/components/conditionality_test.rb +0 -37
  85. data/test/components/container_test.rb +0 -66
  86. data/test/components/content_for_test.rb +0 -60
  87. data/test/components/iterating_test.rb +0 -127
  88. data/test/components/null_wrap_test.rb +0 -28
  89. data/test/components/row_test.rb +0 -16
  90. data/test/components/table_for_test.rb +0 -211
  91. data/test/expander_stack_test.rb +0 -41
  92. data/test/expander_test.rb +0 -99
  93. data/test/markup/tag_test.rb +0 -149
  94. data/test/markup/wrapper_test.rb +0 -42
  95. data/test/markup/yielder_test.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e3c4b0da15f9c3a8e15afd1cd406974c6a77830
4
- data.tar.gz: 4fcaadfa00a739490b71b7a9539778aa3a7019e8
3
+ metadata.gz: 16f46943cd687967eb9ed04ce0beaa6cff6d251a
4
+ data.tar.gz: 04be2d8eae0f12e801b87ba6dfa23367e2c20642
5
5
  SHA512:
6
- metadata.gz: 4ad45dd634f82597ad578c21047556a4770ad76f05b7b92e344fbbde27993dc69a7ff1d53dd3c0c116e9dadc0f444633ea6dc325cf1a7cbcb596179946bea615
7
- data.tar.gz: 1a67f14a59f8eac2b61a840376c0ff2ab1607a2e41533c6fa1543c5caa1ce7811a3d2d0b7b4ca3a66b745d8d38e2cfd99efafbf94d78a056284b187b163ea72b
6
+ metadata.gz: b6bbead39fc3d366d5c11050a2b4b39aa9989f258b9fe5924824b3caa577227b729dfed4abbd66978f9c9bd270831e6b0c24b97cf07949439be5522bcd884aad
7
+ data.tar.gz: 9cd09d8d5fcc54f8e261a09bb4836d14242b14de4e56947c0e0c8e17907b0cc0635640b0e66dc73d12e21e2b2bf5744baec084b69ce024a2392ef52ba9a5c129
data/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Provides a DSL for HTML templates using a declarative style of Ruby as an alternative to Erb or HAML.
4
4
 
5
+ Although originally we implemented our own DSL and used a code generation approach,
6
+ this gem now uses [ActiveAdmin's arbre](https://github.com/activeadmin/arbre). Arbre is widely
7
+ used as part of ActiveAdmin, has a long history and many contributors and is conceptually much simpler.
8
+
5
9
  ## Usage
6
10
 
7
11
  Add this to your gemfile:
@@ -26,7 +30,7 @@ html(lang: "en") {
26
30
  csrf_meta_tags
27
31
  }
28
32
  body {
29
- yield
33
+ current_arbre_element.add_child yield
30
34
  javascript_include_tag "application"
31
35
  }
32
36
  }
@@ -36,35 +40,18 @@ Everything should work as you would expect.
36
40
 
37
41
  Set your editor syntax for .et files to Ruby.
38
42
 
39
- You will now have also be able to utilize components which are found with documentation and examples in <tt>ExpressTemplates::Components<tt>.
40
-
41
- ## History
42
-
43
- To understand ExpressTemplates, you must first understand the standard tools of ERB and Haml which have been with us for quite some time.
44
-
45
- ![Haml/Erb Diagram](https://raw.githubusercontent.com/aelogica/express_templates/master/diagrams/diagram_haml_erb.png "Haml/Erb Diagram")
46
-
47
- Both of these provide a language for embedding other languages. Erb embeds Ruby between <% %> style tags. This is similar to the way we worked with PHP and for those who can remember "embedded Perl" in 1990s. Erb places no constraints on either the text into which the Ruby is embedded, nor on the Ruby which may be placed within the delimiters which comprise Erb's simple grammar.
48
-
49
- Haml introduced a number of innovations or improvements upon Erb. Through Haml's use of significant whitespace and indentation, it ensures well-formed markup. This noticably slows template compilation, however, due to caching it generally goes unnoticed. Haml added better support for mixing grammars in a single file as is common practice with Javascript. Haml introduced abbreviated methods for specifying CSS classes and HTML entity attribute values with the result of generally cleaning up view code.
43
+ You can now utilize components which are found with documentation and examples in <tt>ExpressTemplates::Components<tt>.
50
44
 
51
- Both Haml and Erb compile down to Ruby code which must be eval()'d in a View Context as per the interface required by Rails' ActionView.
45
+ Components are the real strength of both arbre and express_templates.
52
46
 
53
- ## Expansion
47
+ express_templates now *is* arbre + some components + some conventions. ExpressTemplates::Components::Base provides a little syntactic sugar in the form of the emits class method.
54
48
 
55
- ExpressTemplates introduces an earlier step in this process, "expansion", which may be likened to a kind of macro system. This is introduced to facilitate reusable view components in the form of normal object-oriented Ruby classes.
49
+ In terms of conventions, we use brace blocks { } to indicate html structure and do/end blocks to indicate control flow.
56
50
 
57
- ![Diagram depciting Haml/Erb](https://raw.githubusercontent.com/aelogica/express_templates/master/diagrams/diagram_express_templates.png "Diagram depciting Haml/Erb")
51
+ Control flow should only be used in Components. This is currently not enforced but it will be in the future.
58
52
 
59
- ## Constraints - Important!
53
+ The purpose of express_templates is to provide a foundation for a library of reusable UX components which we can enhance for drag-and-drop style UX construction and template editing.
60
54
 
61
- ExpressTemplates imposes some constraints. The most important constraint is that your view templates must be declarative in style. They should not contain conditional logic. Declarative code is easier to read and reason about. It also requires fewer tests since declarative code is build on presumably well-tested primitives.
62
-
63
- With ExpressTemplates, one *must not* place conditional logic or iterators anywhere in template code. All logic *must* be encapsulated in components. Strange things will happen if you try to put logic in the template or a template fragment. In the future I may issue warnings or disallow it by examinging the output of Ruby's tokenizer.
64
-
65
- If you have been around long enough to see a few Rails codebases grow out of control, and you have had to manage or watch the efforts of less-experienced developers closely, you know that one of the major causes of trouble and wasted effort is copy-and-paste code and logic errors in the view. Another common problem is the "blank slate" issue wherein every view must be constructed new with little chance for higher-level reuse of code. Diligent use of partials and helpers can do much to DRY up view code but deciding where to put them or how to share them between projects can be difficult. Rarely is view logic tested except in integration.
66
-
67
- ExpressTemplates only enforces what is already considered a best practice by many, while introducing new possilibities for well-ordered UX libraries similar to what developers working with commercial frameworks for desktop operating systems or mobile devices enjoy.
68
55
 
69
56
  ## Block Structure
70
57
 
@@ -90,8 +77,6 @@ Let us suppose that an @three variable exists in the view context with the value
90
77
  </ul>
91
78
  ```
92
79
 
93
- yield and local variables which we may expect to be available in a ViewContext are also wrapped for evaluation later.
94
-
95
80
  ## Components
96
81
 
97
82
  Given the constraint that logic must not go in the template, where does one put it? The answer is we make a component!
@@ -108,27 +93,23 @@ We can make a simple component like so:
108
93
 
109
94
  ```ruby
110
95
  class ListComponent < ExpressTemplates::Components::Base
111
- emits inner: -> {
112
- li {
113
- item
114
- }
115
- },
116
- outer: -> {
117
- ul {
118
- _yield
119
- }
120
- }
121
-
122
- for_each -> { @list }, emit: :inner
123
-
124
- wrap_with :outer
96
+ emits -> {
97
+ ul {
98
+ # assumes view provides list
99
+ list.each do |item|
100
+ li {
101
+ item
102
+ }
103
+ end
104
+ }
105
+ }
125
106
  end
126
107
  ```
127
108
 
128
109
  This would be used in a view template just as if it were a tag, like so:
129
110
 
130
111
  ```ruby
131
- div.active {
112
+ div(class: "active") {
132
113
  list_component
133
114
  }
134
115
  ```
@@ -0,0 +1,50 @@
1
+ module Arbre
2
+ class Context
3
+ def resource
4
+ helpers.resource
5
+ end
6
+ end
7
+
8
+ class Element
9
+
10
+ module BuilderMethods
11
+
12
+ # we do not want to check the arity of the
13
+ # block in express templates because components
14
+ # are expected to be able to contain other components or template code
15
+ # without use of a builder style syntax
16
+ def build_tag(klass, *args, &block)
17
+ tag = klass.new(arbre_context)
18
+ tag.parent = current_arbre_element
19
+
20
+ with_current_arbre_element tag do
21
+ tag.build(*args, &block)
22
+ end
23
+
24
+ tag
25
+ end
26
+ end
27
+
28
+ # Implements the method lookup chain. When you call a method that
29
+ # doesn't exist, we:
30
+ #
31
+ # 1. Try to call the method on the current DOM context
32
+ # 2. Return an assigned variable of the same name
33
+ # 3. Call the method on the helper object
34
+ # 4. Call super
35
+ #
36
+ def method_missing(name, *args, &block)
37
+ if current_arbre_element.respond_to?(name)
38
+ current_arbre_element.send name, *args, &block
39
+ elsif assigns && assigns.has_key?(name)
40
+ assigns[name]
41
+ elsif helpers.respond_to?(name)
42
+ current_arbre_element.add_child helpers.send(name, *args, &block)
43
+ else
44
+ super
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -24,6 +24,7 @@ class Proc
24
24
  def source
25
25
  @source ||= begin
26
26
  file, line_no = source_location
27
+ raise "no file provided by source_location: #{self}" if file.nil?
27
28
  raise "no line number provided for source_location: #{self}" if line_no.nil?
28
29
  tokens = Ripper.lex File.read(file)
29
30
  tokens_on_line = tokens.select {|pos, lbl, str| pos[0].eql?(line_no) }
@@ -1,3 +1,4 @@
1
+ require 'ostruct'
1
2
  module ExpressTemplates
2
3
  module Compiler
3
4
  def compile(template_or_src=nil, &block)
@@ -12,13 +13,7 @@ module ExpressTemplates
12
13
 
13
14
  template, src = _normalize(template_or_src)
14
15
 
15
- expander = Expander.new(template)
16
-
17
- compiled = expander.expand(src, &block).map(&:compile)
18
-
19
- return Interpolator.transform(compiled.join("+").gsub('"+"', '')).tap do |s|
20
- puts("\n"+template.inspect+"\nSource:\n#{template.try(:source)}\nInterpolated:\n#{s}\n") if ENV['DEBUG'].eql?('true')
21
- end
16
+ %Q[Arbre::Context.new(assigns.merge(template_virtual_path: @virtual_path), self) { #{src || block.source_body} }.to_s]
22
17
  end
23
18
 
24
19
  private
@@ -5,50 +5,46 @@ module ExpressTemplates
5
5
  # Components provide self-contained reusable view code meant to be shared
6
6
  # within a project or across many projects through a library of components
7
7
  #
8
- # Components gain their functionality through inclusion of Capabilities.
9
- #
10
- # Most Components are descendents of Components::Base.
11
- #
12
8
  module Components
13
9
 
14
10
  # Components::Base is the base class for ExpressTemplates view components.
15
11
  #
16
- # View components are available as macros in ExpressTemplates and may be
17
- # used to encapsulate common view patterns, behavior and functionality in
18
- # reusable classes that can be shared within and across projects.
19
- #
20
- # Components intended to provide a base framework for a library of reusable
21
- # components to cut development time across a multitude of projects.
22
- #
23
- # Components gain their functionality through including Capabilities.
24
- #
25
- # Example capabilities include:
26
- #
27
- # * Managing related ExpressTemplate fragments
28
- # * Compiling template fragments for evaluation in a View Context
29
- # * Specifying rendering logic to be executed in the View Context
30
- # * Potentially referencing external assets that may be required
31
- # for the component to work.
32
12
  #
33
- # Components::Base includes the following capabilities:
34
- #
35
- # * Capabilities::Templating
36
- # * Capabilities::Rendering
37
- # * Capabilities::Wrapping
38
- # * Capabilities::Iterating
39
- #
40
- class Base < Expander
41
- include ExpressTemplates::Macro
42
- include Capabilities::Templating
43
- include Capabilities::Rendering
44
- include Capabilities::Wrapping
45
- include Capabilities::Iterating
46
-
47
- def self.inherited(klass)
48
- ExpressTemplates::Expander.register_macros_for klass
13
+ class Base < Arbre::Component
14
+
15
+ def self.builder_method_and_class(method_name, klass)
16
+ Arbre::Element::BuilderMethods.class_eval <<-EOF, __FILE__, __LINE__
17
+ def #{method_name}(*args, &block)
18
+ insert_tag ::#{klass.name}, *args, &block
19
+ end
20
+ EOF
21
+ # puts "added #{method_name} -> #{klass.name}"
49
22
  end
50
23
 
51
- end
24
+ def self.emits(proc = nil, &block)
25
+ define_method(:build, &(proc || block))
26
+ end
52
27
 
28
+ def build(*args, block)
29
+ raise "#build method must be overridden"
30
+ end
31
+
32
+ def resource
33
+ helpers.resource
34
+ end
35
+
36
+ def self.inherited(subclass)
37
+ builder_method_and_class subclass.to_s.demodulize.underscore, subclass
38
+ end
39
+
40
+ def indent_level
41
+ parent_indent_level = parent.try(:indent_level) || 0
42
+ end
43
+
44
+ def to_s
45
+ children.to_s
46
+ end
47
+
48
+ end
53
49
  end
54
50
  end
@@ -4,15 +4,15 @@ module ExpressTemplates
4
4
 
5
5
  module Resourceful
6
6
  def namespace
7
- @config[:namespace] || infer_namespace
7
+ config[:namespace] || infer_namespace
8
8
  end
9
9
 
10
10
  def path_prefix
11
- @config[:path_prefix] || infer_path_prefix
11
+ config[:path_prefix] || infer_path_prefix
12
12
  end
13
13
 
14
14
  def resource_class
15
- resource_class = @config[:resource_class] || _namespaced_resource_class
15
+ resource_class = config[:resource_class] || _namespaced_resource_class
16
16
  resource_class.constantize
17
17
  end
18
18
 
@@ -26,10 +26,17 @@ module ExpressTemplates
26
26
  end
27
27
  end
28
28
 
29
+ def template_virtual_path
30
+ begin
31
+ super
32
+ rescue
33
+ nil
34
+ end
35
+ end
36
+
29
37
  def infer_namespace
30
- expander = @args.last
31
- if expander.try(:template)
32
- path_parts = expander.template.virtual_path.split('/')
38
+ if template_virtual_path
39
+ path_parts = template_virtual_path.split('/')
33
40
 
34
41
  case
35
42
  when path_parts.size == 4
@@ -50,9 +57,8 @@ module ExpressTemplates
50
57
  end
51
58
 
52
59
  def infer_path_prefix
53
- expander = @args.last
54
- if expander.try(:template)
55
- path_parts = expander.template.virtual_path.split('/')
60
+ if template_virtual_path
61
+ path_parts = template_virtual_path.split('/')
56
62
 
57
63
  case
58
64
  when path_parts.size == 4
@@ -75,7 +81,7 @@ module ExpressTemplates
75
81
  # TODO: this can now be inferred from the template.virtual_path
76
82
  # if not supplied...
77
83
  def resource_name
78
- @config[:id].to_s.singularize
84
+ config[:id].to_s.singularize
79
85
  end
80
86
 
81
87
  def collection_member_name
@@ -91,14 +97,15 @@ module ExpressTemplates
91
97
  end
92
98
 
93
99
  def collection
94
- @config[:collection] || collection_var
100
+ config[:collection] || helpers.collection
95
101
  end
96
102
 
97
103
  def collection_path
98
- if @config[:collection_path]
99
- @config[:collection_path]
104
+ if config[:collection_path]
105
+ config[:collection_path]
100
106
  else
101
- "#{collection_name_with_prefix}_path"
107
+ #super
108
+ helpers.instance_eval "#{collection_name_with_prefix}_path"
102
109
  end
103
110
  end
104
111
 
@@ -110,11 +117,16 @@ module ExpressTemplates
110
117
  end
111
118
  end
112
119
 
120
+ def resource_path_helper
121
+ "#{resource_name_with_path_prefix}_path"
122
+ end
123
+
113
124
  def resource_path(ivar=false)
114
- if @config[:resource_path]
115
- @config[:resource_path]
125
+ if config[:resource_path]
126
+ config[:resource_path]
116
127
  else
117
- "#{resource_name_with_path_prefix}_path(#{ivar ? '@' : ''}#{resource_name})"
128
+ # super
129
+ helpers.instance_eval("#{resource_path_helper}(#{ivar ? '@' : ''}#{resource_name})")
118
130
  end
119
131
  end
120
132
 
@@ -126,7 +138,7 @@ module ExpressTemplates
126
138
  end
127
139
  end
128
140
 
129
- def attributes
141
+ def resource_attributes
130
142
  resource_class.columns
131
143
  end
132
144
  end
@@ -0,0 +1,41 @@
1
+ module ExpressTemplates
2
+ module Components
3
+ class Configurable < Base
4
+
5
+ def self.emits(proc = nil, &block)
6
+ define_method(:markup, &(proc || block))
7
+ end
8
+
9
+ def build(*args, &block)
10
+ _process_args!(args)
11
+ if method(:markup).arity > 0
12
+ markup(block)
13
+ else
14
+ markup(&block)
15
+ end
16
+ end
17
+
18
+ def config
19
+ @config ||= {}
20
+ end
21
+
22
+ alias :my :config
23
+
24
+
25
+ protected
26
+
27
+ def _process_args!(args)
28
+ if args.first.kind_of?(Symbol)
29
+ config.merge!(id: args.shift)
30
+ attributes[:id] = config[:id]
31
+ end
32
+ args.each do |arg|
33
+ if arg.kind_of?(Hash)
34
+ config.merge!(arg)
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -5,16 +5,15 @@ module ExpressTemplates
5
5
  # would be provided by Rails' form helpers.
6
6
  #
7
7
  # An optional method may be speficied. Defaults to 'post'.
8
- class FormRailsSupport < Base
9
- include Capabilities::Configurable
10
- emits -> {
8
+ class FormRailsSupport < Configurable
9
+ emits -> (ctx) {
11
10
  div(style: 'display:none') {
12
- utf8_enforcer_tag
11
+ add_child helpers.utf8_enforcer_tag
13
12
  # NOTE: This should be moved into the forms module and made a FormComponent
14
13
  # to have access to the resource_name as this code assumes existence of
15
14
  # a resource method which may not exist
16
- method_tag(@config[:id] || "{{((resource.persisted? ? :put : :post) rescue :post)}}")
17
- token_tag
15
+ add_child helpers.send(:method_tag, (config[:id] || ((resource.persisted? ? :put : :post) rescue :post)))
16
+ helpers.send(:token_tag)
18
17
  }
19
18
  }
20
19
  end
@@ -12,7 +12,7 @@ module ExpressTemplates
12
12
  emits -> {
13
13
  div(class: field_wrapper_class) {
14
14
  label_tag(label_name, label_text)
15
- #{type}_field resource_var, field_name.to_sym
15
+ #{type}_field resource_var, field_name.to_sym, html_options
16
16
  }
17
17
  }
18
18
  end
@@ -35,19 +35,16 @@ RUBY
35
35
  emits -> {
36
36
  div(class: field_wrapper_class) {
37
37
  label_tag(label_name, label_text)
38
- text_area resource_var, field_name.to_sym
38
+ text_area resource_var, field_name.to_sym, html_options
39
39
  }
40
40
  }
41
41
  end
42
42
 
43
43
  class Hidden < FormComponent
44
44
  emits -> {
45
- hidden_field resource_var, field_name.to_sym
45
+ hidden_field resource_var, field_name.to_sym, html_options
46
46
  }
47
47
  end
48
-
49
-
50
48
  end
51
49
  end
52
50
  end
53
-
@@ -16,7 +16,7 @@ module ExpressTemplates
16
16
  end
17
17
 
18
18
  def label_after?
19
- !!@config[:label_after]
19
+ !!config[:label_after]
20
20
  end
21
21
 
22
22
  def field_options
@@ -1,55 +1,45 @@
1
1
  module ExpressTemplates
2
2
  module Components
3
3
  module Forms
4
- class ExpressForm < Base
5
- include Capabilities::Configurable
6
- include Capabilities::Parenting
7
- include Capabilities::Resourceful
8
- include Forms::FormSupport
9
-
10
- emits -> {
11
- form( form_args ) {
4
+ class ExpressForm < Configurable
5
+ include ExpressTemplates::Components::Capabilities::Resourceful
6
+
7
+ emits -> (block) {
8
+ form(form_tag_options ) {
12
9
  form_rails_support form_method
13
- _yield
10
+ block.call(self) if block
14
11
  }
15
12
  }
16
13
 
17
14
  def form_id
18
- "#{resource_name}_{{@#{resource_name}.id}}"
15
+ "#{resource_name}_#{resource.id}"
19
16
  end
20
17
 
21
18
  def form_method
22
- @config[:method]
19
+ config[:method].to_s.upcase || 'POST'
23
20
  end
24
21
 
22
+ def form_action
23
+ config[:action] || (resource.try(:persisted?) ? resource_path(ivar: true) : collection_path)
24
+ end
25
25
 
26
- def form_args
27
- # there are no put/patch emthods in HTML5, so we have to enforce post
28
- # need to find a better way to do this: id/action can be overridden but method
29
- # should always be :post IN THE FORM TAG
30
- args = {id: form_id, action: form_action}.merge!(@config).merge!(method: :post)
26
+ def form_tag_options
27
+ args = {id: form_id, action: form_action}.merge!(config).merge!(method: 'POST')
31
28
 
32
29
  if html_options = args.delete(:html_options)
33
30
  args.merge!(html_options)
34
31
  end
35
- args[:method] = args[:method].to_s.upcase
36
32
  args
37
33
  end
38
34
 
39
35
  def resource_name_for_path
40
- @config[:id].to_s
36
+ config[:id].to_s
41
37
  end
42
38
 
43
39
  def resource_name
44
- (@config[:resource_name] || @config[:id]).to_s
40
+ (config[:resource_name] || config[:id]).to_s
45
41
  end
46
42
 
47
- private
48
-
49
- def _modifying_resource?
50
- [:put, :patch].include? form_method
51
- end
52
-
53
43
  end
54
44
  end
55
45
  end
@@ -1,17 +1,11 @@
1
1
  module ExpressTemplates
2
2
  module Components
3
3
  module Forms
4
- class FormComponent < Base
5
- include Capabilities::Configurable
6
- include Capabilities::Adoptable
7
-
8
- def compile(*args)
9
- raise "#{self.class} requires a parent ExpressForm" if parent.nil? or parent_form.nil?
10
- super(*args)
11
- end
4
+ class FormComponent < Configurable
12
5
 
13
6
  # Lookup the resource_name from the parent ExpressForm.
14
7
  def resource_name
8
+ raise "FormComponent must have a parent form" unless parent_form
15
9
  parent_form.resource_name
16
10
  end
17
11
 
@@ -30,13 +24,13 @@ module ExpressTemplates
30
24
 
31
25
  # Return the text content for the label
32
26
  def label_text
33
- @config[:label] || field_name.titleize
27
+ config[:label] || field_name.titleize
34
28
  end
35
29
 
36
30
  # Return the field_name as a string. This taken from the first argument
37
31
  # to the component macro in the template or fragment.
38
32
  def field_name
39
- (@config[:id] || (@args.first.is_a?(String) && @args.first)).to_s
33
+ (config[:id] || (@args.first.is_a?(String) && @args.first)).to_s
40
34
  end
41
35
 
42
36
  # Return the field name attribute. Currently handles only simple attributes
@@ -46,7 +40,7 @@ module ExpressTemplates
46
40
  end
47
41
 
48
42
  def field_wrapper_class
49
- @config[:wrapper_class] || 'field-wrapper'
43
+ config[:wrapper_class] || 'field-wrapper'
50
44
  end
51
45
 
52
46
  # Search the parent graph until we find an ExpressForm. Returns nil if none found.
@@ -58,6 +52,21 @@ module ExpressTemplates
58
52
  return @my_form
59
53
  end
60
54
 
55
+ def default_html_options
56
+ (config || {}).reject {|k,v| k.eql?(:id)}
57
+ end
58
+
59
+ def html_options
60
+ default_html_options.merge(config[:html_options] || {})
61
+ end
62
+
63
+ protected
64
+
65
+ def _process_args!(args)
66
+ @args = args
67
+ super(args)
68
+ end
69
+
61
70
  end
62
71
  end
63
72
  end
@@ -28,9 +28,9 @@ module ExpressTemplates
28
28
  reflection = belongs_to_association || has_many_through_association
29
29
  if reflection && !reflection.polymorphic?
30
30
  if cols.detect {|column| column.name.eql?('name') }
31
- "#{reflection.klass}.all.select(:#{option_value_method}, :#{option_name_method}).order(:#{option_name_method})"
31
+ reflection.klass.select(option_value_method.to_sym, option_name_method.to_sym).order(option_name_method.to_sym)
32
32
  else
33
- "#{reflection.klass}.all.sort_by(&:#{option_name_method})"
33
+ reflection.klass.all.sort_by(&option_name_method.to_sym)
34
34
  end
35
35
  end
36
36
  end