forme 0.10.0 → 1.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 610c1c28c2ed6fc3c4f36d520c4e67fea4fa9c1f
4
- data.tar.gz: 7bb48306b738007c7c40c0673ad964c94f1e4c0d
3
+ metadata.gz: 9fb6883778ebb616402a910c3f46f7bd6ba3734b
4
+ data.tar.gz: aed74dd741f94bb368e97390d14a4000f4b73f39
5
5
  SHA512:
6
- metadata.gz: a6076239cb78c5f4ad271fb77d5b65947f75899243633e49281ae0d2c350799d134d4deb542aa8129e912f427a0a46ce195bd5f21d34904ab1505e738aab75dd
7
- data.tar.gz: de392606364637b2b8999151ff18854bbc0e0b2ec62d54f123ce563b986814e5311154b7c825687274dc16f4e5b579cc0f6a44f5a37c34d08338ee93214cd939
6
+ metadata.gz: 297661c5e245fcbb2f7c671d59c79f77b4d07d3bcded836ace5c7a6049f237b3d7711923178dcfcfdc3ac704a654b491c217112d114f033bd9d241f2c3f9b2f4
7
+ data.tar.gz: 68d7a1d1adbae977f2c26649a72633ae2c954f8701bca70883153eac44fe86113aedd1a47015ad261f2e91ad119945aab56355d54480dda0782bc11896557b26
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ === 1.0.0 (2014-07-30)
2
+
3
+ * Add roda plugin for forme (jeremyevans)
4
+
5
+ * Move forme/sinatra to forme/erb, since it is ERB and not Sinatra specific (jeremyevans)
6
+
7
+ * Do not extend objects at runtime when using the Sequel support (jeremyevans)
8
+
1
9
  === 0.10.0 (2014-07-01)
2
10
 
3
11
  * Use #[] instead of #send to get input value for object forms if object is a hash (jeremyevans)
data/lib/forme.rb CHANGED
@@ -148,6 +148,16 @@ module Forme
148
148
  # Must respond to +call+ or be a registered symbol.
149
149
  attr_reader :serializer
150
150
 
151
+ # Use appropriate Form subclass for object based on the current class, if the
152
+ # object responds to +forme_form_class+.
153
+ def self.new(obj=nil, opts={})
154
+ if obj && obj.respond_to?(:forme_form_class) && !opts[:_forme_form_class_set]
155
+ obj.forme_form_class(self).new(obj, opts.merge(:_forme_form_class_set=>true))
156
+ else
157
+ super
158
+ end
159
+ end
160
+
151
161
  # Create a +Form+ instance and yield it to the block,
152
162
  # injecting the opening form tag before yielding and
153
163
  # the closing form tag after yielding.
@@ -403,6 +413,13 @@ module Forme
403
413
  end
404
414
  end
405
415
 
416
+ # Marks the string as containing already escaped output. Returns string given
417
+ # by default, but subclasses for specific web frameworks can handle automatic
418
+ # html escaping by overriding this.
419
+ def raw_output(s)
420
+ s
421
+ end
422
+
406
423
  # Temporarily override the given object and namespace for the form. Any given
407
424
  # namespaces are appended to the form's current namespace.
408
425
  def with_obj(obj, namespace=nil)
@@ -471,6 +488,16 @@ module Forme
471
488
  ensure
472
489
  @nesting.pop
473
490
  end
491
+
492
+ # Return a serialized opening tag for the given tag.
493
+ def serialize_open(tag)
494
+ raw_output(serializer.serialize_open(tag)) if serializer.respond_to?(:serialize_open)
495
+ end
496
+
497
+ # Return a serialized closing tag for the given tag.
498
+ def serialize_close(tag)
499
+ raw_output(serializer.serialize_close(tag)) if serializer.respond_to?(:serialize_close)
500
+ end
474
501
  end
475
502
 
476
503
  # High level abstract tag form, transformed by formatters into the lower
@@ -510,7 +537,7 @@ module Forme
510
537
 
511
538
  # Return a string containing the serialized content of the receiver.
512
539
  def to_s
513
- Forme.transform(:serializer, @opts, @form_opts, self)
540
+ form.raw_output(Forme.transform(:serializer, @opts, @form_opts, self))
514
541
  end
515
542
 
516
543
  # Transform the receiver into a lower level +Tag+ form (or an array
@@ -559,7 +586,7 @@ module Forme
559
586
 
560
587
  # Return a string containing the serialized content of the receiver.
561
588
  def to_s
562
- Forme.transform(:serializer, @opts, @form.opts, self)
589
+ form.raw_output(Forme.transform(:serializer, @opts, @form.opts, self))
563
590
  end
564
591
 
565
592
  private
data/lib/forme/erb.rb ADDED
@@ -0,0 +1,104 @@
1
+ require 'forme'
2
+
3
+ module Forme
4
+ module ERB
5
+ HIDDEN_TAGS = []
6
+
7
+ # Add a hidden tag proc that will be used for all forms created via Forme::ERB::Helper#form.
8
+ # The block is yielded the Forme::Tag object for the form tag.
9
+ # The block should return either nil if hidden tag should be added, or a Forme::Tag object (or an array of them),
10
+ # or a hash with keys specifying the name of the tags and the values specifying the values of the tags .
11
+ def self.add_hidden_tag(&block)
12
+ HIDDEN_TAGS << block
13
+ end
14
+
15
+ # Add CSRF token tag by default for POST forms
16
+ add_hidden_tag do |tag|
17
+ if defined?(::Rack::Csrf) && (form = tag.form) && (env = form.opts[:env]) && tag.attr[:method].to_s.upcase == 'POST'
18
+ {::Rack::Csrf.field=>::Rack::Csrf.token(env)}
19
+ end
20
+ end
21
+
22
+ # Subclass used when using Forme ERB integration.
23
+ # Handles integrating into the view template so that
24
+ # methods with blocks can inject strings into the output.
25
+ class Form < ::Forme::Form
26
+ # Template output object, where serialized output gets
27
+ # injected.
28
+ attr_reader :output
29
+
30
+ # Set the template output object when initializing.
31
+ def initialize(*)
32
+ super
33
+ @output = @opts[:output] ? @opts[:output] : ''
34
+ end
35
+
36
+ # Serialize the tag and inject it into the output.
37
+ def emit(tag)
38
+ output << tag.to_s
39
+ end
40
+
41
+ # Capture the inside of the inputs, injecting it into the template
42
+ # if a block is given, or returning it as a string if not.
43
+ def inputs(*a, &block)
44
+ if block
45
+ capture(block){super}
46
+ else
47
+ capture{super}
48
+ end
49
+ end
50
+
51
+ # Capture the inside of the form, injecting it into the template if
52
+ # a block is given, or returning it as a string if not.
53
+ def form(*a, &block)
54
+ if block
55
+ capture(block){super}
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ # If a block is given, inject an opening tag into the
62
+ # output, inject any given children into the output, yield to the
63
+ # block, inject a closing tag into the output.
64
+ # If a block is not given, just return the tag created.
65
+ def tag(type, attr={}, children=[], &block)
66
+ tag = _tag(type, attr, children)
67
+ if block
68
+ capture(block) do
69
+ emit(serialize_open(tag))
70
+ Array(tag.children).each{|c| emit(c)}
71
+ yield self
72
+ emit(serialize_close(tag))
73
+ end
74
+ else
75
+ tag
76
+ end
77
+ end
78
+
79
+ def capture(block='') # :nodoc:
80
+ buf_was, @output = @output, block.is_a?(Proc) ? (eval("@_out_buf", block.binding) || @output) : block
81
+ yield
82
+ ret = @output
83
+ @output = buf_was
84
+ ret
85
+ end
86
+ end
87
+
88
+ # This is the module used to add the Forme integration
89
+ # to ERB.
90
+ module Helper
91
+ # Create a +Form+ object tied to the current output buffer,
92
+ # using the standard ERB hidden tags.
93
+ def form(obj=nil, attr={}, opts={}, &block)
94
+ if block
95
+ h = {:output=>@_out_buf, :hidden_tags=>Forme::ERB::HIDDEN_TAGS, :env=>env}
96
+ (obj.is_a?(Hash) ? attr = attr.merge(h) : opts = opts.merge(h))
97
+ Form.form(obj, attr, opts, &block)
98
+ else
99
+ Form.form(obj, attr, opts)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
data/lib/forme/rails.rb CHANGED
@@ -38,7 +38,7 @@ module Forme
38
38
  # Serialize and mark as already escaped the string version of
39
39
  # the input.
40
40
  def emit(tag)
41
- template.output_buffer << template.raw(tag.to_s)
41
+ template.output_buffer << tag.to_s
42
42
  end
43
43
 
44
44
  # Capture the inputs into a new output buffer, and return
@@ -63,12 +63,17 @@ module Forme
63
63
 
64
64
  # Return a string version of the input that is already marked as safe.
65
65
  def input(*)
66
- template.raw(super.to_s)
66
+ super.to_s
67
67
  end
68
68
 
69
69
  # Return a string version of the button that is already marked as safe.
70
70
  def button(*)
71
- template.raw(super.to_s)
71
+ super.to_s
72
+ end
73
+
74
+ # Use the template's raw method to mark the given string as html safe.
75
+ def raw_output(s)
76
+ template.raw(s)
72
77
  end
73
78
 
74
79
  # If a block is given, create a new output buffer and make sure all the
@@ -79,37 +84,22 @@ module Forme
79
84
  if block_given?
80
85
  template.send(:with_output_buffer){tag_(type, attr, children, &block)}
81
86
  else
82
- tag = _tag(type, attr, children)
83
- template.raw(tag.to_s)
87
+ _tag(type, attr, children).to_s
84
88
  end
85
89
  end
86
90
 
87
91
  def tag_(type, attr={}, children=[]) # :nodoc:
88
92
  tag = _tag(type, attr, children)
89
- emit(serializer.serialize_open(tag)) if serializer.respond_to?(:serialize_open)
93
+ emit(serialize_open(tag))
90
94
  Array(tag.children).each{|c| emit(c)}
91
95
  yield self if block_given?
92
- emit(serializer.serialize_close(tag)) if serializer.respond_to?(:serialize_close)
96
+ emit(serialize_close(tag))
93
97
  end
94
98
  end
95
99
 
96
100
  module ERB
97
- # Create a +Form+ object and yield it to the block,
98
- # injecting the opening form tag before yielding and
99
- # the closing form tag after yielding.
100
- #
101
- # Argument Handling:
102
- # No args :: Creates a +Form+ object with no options and not associated
103
- # to an +obj+, and with no attributes in the opening tag.
104
- # 1 hash arg :: Treated as opening form tag attributes, creating a
105
- # +Form+ object with no options.
106
- # 1 non-hash arg :: Treated as the +Form+'s +obj+, with empty options
107
- # and no attributes in the opening tag.
108
- # 2 hash args :: First hash is opening attributes, second hash is +Form+
109
- # options.
110
- # 1 non-hash arg, 1-2 hash args :: First argument is +Form+'s obj, second is
111
- # opening attributes, third if provided is
112
- # +Form+'s options.
101
+ # Create a +Form+ object tied to the current template, and using the standard
102
+ # Rails hidden tags.
113
103
  def forme(obj=nil, attr={}, opts={}, &block)
114
104
  h = {:template=>self, :hidden_tags=>Forme::Rails::HIDDEN_TAGS}
115
105
  (obj.is_a?(Hash) ? attr = attr.merge(h) : opts = opts.merge(h))
data/lib/forme/sinatra.rb CHANGED
@@ -1,124 +1,15 @@
1
- require 'forme'
1
+ require 'forme/erb'
2
2
 
3
3
  module Forme
4
+ # For backwards compatibility only. New code should
5
+ # require 'forme/erb' and include the Forme::ERB::Helper
6
+ # class:
7
+ #
8
+ # helpers Forme::ERB::Helper
4
9
  module Sinatra
5
- HIDDEN_TAGS = []
6
-
7
- # Add a hidden tag proc that will be used for all forms created via Forme::Sinatra::ERB#form.
8
- # The block is yielded the Forme::Tag object for the form tag.
9
- # The block should return either nil if hidden tag should be added, or a Forme::Tag object (or an array of them),
10
- # or a hash with keys specifying the name of the tags and the values specifying the values of the tags .
11
- def self.add_hidden_tag(&block)
12
- HIDDEN_TAGS << block
13
- end
14
-
15
- # Add CSRF token tag by default for POST forms
16
- add_hidden_tag do |tag|
17
- if defined?(::Rack::Csrf) && (form = tag.form) && (env = form.opts[:env]) && tag.attr[:method].to_s.upcase == 'POST'
18
- {::Rack::Csrf.field=>::Rack::Csrf.token(env)}
19
- end
20
- end
21
-
22
- # Subclass used when using Forme/Sinatra ERB integration.
23
- # Handles integrating into the view template so that
24
- # methods with blocks can inject strings into the output.
25
- class Form < ::Forme::Form
26
- # Template output object, where serialized output gets
27
- # injected.
28
- attr_reader :output
29
-
30
- # Set the template output object when initializing.
31
- def initialize(*)
32
- super
33
- @output = @opts[:output] ? @opts[:output] : ''
34
- end
35
-
36
- # Serialize the tag and inject it into the output.
37
- def emit(tag)
38
- output << tag.to_s
39
- end
40
-
41
- # Capture the inside of the inputs, injecting it into the template
42
- # if a block is given, or returning it as a string if not.
43
- def inputs(*a, &block)
44
- if block
45
- capture(block){super}
46
- else
47
- capture{super}
48
- end
49
- end
50
-
51
- # Capture the inside of the form, injecting it into the template if
52
- # a block is given, or returning it as a string if not.
53
- def form(*a, &block)
54
- if block
55
- capture(block){super}
56
- else
57
- super
58
- end
59
- end
60
-
61
- # If a block is given, inject an opening tag into the
62
- # output, inject any given children into the output, yield to the
63
- # block, inject a closing tag into the output.
64
- # If a block is not given, just return the tag created.
65
- def tag(type, attr={}, children=[], &block)
66
- tag = _tag(type, attr, children)
67
- if block
68
- capture(block) do
69
- emit(serializer.serialize_open(tag)) if serializer.respond_to?(:serialize_open)
70
- Array(tag.children).each{|c| emit(c)}
71
- yield self
72
- emit(serializer.serialize_close(tag)) if serializer.respond_to?(:serialize_close)
73
- end
74
- else
75
- tag
76
- end
77
- end
78
-
79
- def capture(block='')
80
- buf_was, @output = @output, block.is_a?(Proc) ? (eval("@_out_buf", block.binding) || @output) : block
81
- yield
82
- ret = @output
83
- @output = buf_was
84
- ret
85
- end
86
- end
87
-
88
- # This is the module used to add the Forme integration
89
- # to Sinatra. It should be enabled in Sinatra with the
90
- # following code in your <tt>Sinatra::Base</tt> subclass:
91
- #
92
- # helpers Forme::Sinatra::ERB
93
- module ERB
94
- # Create a +Form+ object and yield it to the block,
95
- # injecting the opening form tag before yielding and
96
- # the closing form tag after yielding.
97
- #
98
- # Argument Handling:
99
- # No args :: Creates a +Form+ object with no options and not associated
100
- # to an +obj+, and with no attributes in the opening tag.
101
- # 1 hash arg :: Treated as opening form tag attributes, creating a
102
- # +Form+ object with no options.
103
- # 1 non-hash arg :: Treated as the +Form+'s +obj+, with empty options
104
- # and no attributes in the opening tag.
105
- # 2 hash args :: First hash is opening attributes, second hash is +Form+
106
- # options.
107
- # 1 non-hash arg, 1-2 hash args :: First argument is +Form+'s obj, second is
108
- # opening attributes, third if provided is
109
- # +Form+'s options.
110
- def form(obj=nil, attr={}, opts={}, &block)
111
- if block
112
- h = {:output=>@_out_buf, :hidden_tags=>Forme::Sinatra::HIDDEN_TAGS, :env=>env}
113
- (obj.is_a?(Hash) ? attr = attr.merge(h) : opts = opts.merge(h))
114
- Form.form(obj, attr, opts, &block)
115
- else
116
- Form.form(obj, attr, opts)
117
- end
118
- end
119
- end
120
-
121
- # Alias of <tt>Forme::Sinatra::ERB</tt>
10
+ ERB = Forme::ERB::Helper
122
11
  Erubis = ERB
12
+ Form = Forme::ERB::Form
13
+ HIDDEN_TAGS = Forme::ERB::HIDDEN_TAGS
123
14
  end
124
15
  end
data/lib/forme/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Forme
2
2
  # Version constant, use <tt>Forme.version</tt> instead.
3
- VERSION = '0.10.0'.freeze
3
+ VERSION = '1.0.0'.freeze
4
4
 
5
5
  # Returns the version as a frozen string (e.g. '0.1.0')
6
6
  def self.version
@@ -0,0 +1,17 @@
1
+ require 'forme/erb'
2
+
3
+ class Roda
4
+ module RodaPlugins
5
+ module Forme
6
+ # Require the render plugin, since forme template integration
7
+ # only makes sense with it.
8
+ def self.load_dependencies(app)
9
+ app.plugin :render
10
+ end
11
+
12
+ InstanceMethods = ::Forme::ERB::Helper
13
+ end
14
+
15
+ register_plugin(:forme, Forme)
16
+ end
17
+ end
@@ -1,4 +1,5 @@
1
1
  require 'forme'
2
+ require 'thread'
2
3
 
3
4
  module Sequel # :nodoc:
4
5
  module Plugins # :nodoc:
@@ -418,9 +419,9 @@ module Sequel # :nodoc:
418
419
  end
419
420
  end
420
421
 
421
- # Helper module used for Sequel/Sinatra forms. Necessary for
422
+ # Helper module used for Sequel forms using ERB template integration. Necessary for
422
423
  # proper subform handling when using such forms with partials.
423
- module SinatraSequelForm
424
+ module ERBSequelForm
424
425
  # Capture the inside of the inputs, injecting it into the template
425
426
  # if a block is given, or returning it as a string if not.
426
427
  def subform(*, &block)
@@ -431,14 +432,31 @@ module Sequel # :nodoc:
431
432
  end
432
433
  end
433
434
  end
435
+ SinatraSequelForm = ERBSequelForm
436
+
437
+ class Form < ::Forme::Form
438
+ include SequelForm
439
+ end
434
440
 
435
441
  module InstanceMethods
442
+ MUTEX = Mutex.new
443
+ FORM_CLASSES = {::Forme::Form=>Form}
444
+
436
445
  # Configure the +form+ with support for <tt>Sequel::Model</tt>
437
446
  # specific code, such as support for nested attributes.
438
447
  def forme_config(form)
439
- form.extend(SequelForm)
440
448
  form.namespaces << model.send(:underscore, model.name)
441
- form.extend(SinatraSequelForm) if defined?(::Forme::Sinatra::Form) && form.is_a?(::Forme::Sinatra::Form)
449
+ end
450
+
451
+ # Return subclass of base form that includes the necessary Sequel form methods.
452
+ def forme_form_class(base)
453
+ unless klass = MUTEX.synchronize{FORM_CLASSES[base]}
454
+ klass = Class.new(base)
455
+ klass.send(:include, SequelForm)
456
+ klass.send(:include, ERBSequelForm) if defined?(::Forme::ERB::Form) && base == ::Forme::ERB::Form
457
+ MUTEX.synchronize{FORM_CLASSES[base] = klass}
458
+ end
459
+ klass
442
460
  end
443
461
 
444
462
  # Return <tt>Forme::Input</tt> instance based on the given arguments.
@@ -0,0 +1,177 @@
1
+ ERB_BLOCK = lambda do |r|
2
+ r.get '' do
3
+ erb <<END
4
+ <% form([:foo, :bar], :action=>'/baz') do |f| %>
5
+ <p>FBB</p>
6
+ <%= f.input(:first) %>
7
+ <%= f.input(:last) %>
8
+ <%= f.button('Save') %>
9
+ <% end %>
10
+ END
11
+ end
12
+
13
+ r.get 'inputs_block' do
14
+ erb <<END
15
+ <% form([:foo, :bar], :action=>'/baz') do |f| %><% f.inputs(:legend=>'FBB') do %>
16
+ <%= f.input(:last) %>
17
+ <% end %><% end %>
18
+ END
19
+ end
20
+
21
+ r.get 'inputs_block_wrapper' do
22
+ erb <<END
23
+ <% form([:foo, :bar], {:action=>'/baz'}, :inputs_wrapper=>:fieldset_ol) do |f| %><% f.inputs(:legend=>'FBB') do %>
24
+ <%= f.input(:last) %>
25
+ <% end %><% end %>
26
+ END
27
+ end
28
+
29
+ r.get 'nest' do
30
+ erb <<END
31
+ <% form([:foo, :bar], :action=>'/baz') do |f| %>
32
+ <%= f.tag(:p, {}, 'FBB') %>
33
+ <% f.tag(:div) do %>
34
+ <%= f.input(:first) %>
35
+ <%= f.input(:last) %>
36
+ <% end %>
37
+
38
+ <% end %>
39
+ END
40
+ end
41
+
42
+ r.get 'nest_sep' do
43
+ @nest = <<END
44
+ n1
45
+ <% f.tag(:div) do %>
46
+ n2
47
+ <%= f.input(:first) %>
48
+ <%= f.input(:last) %>
49
+ n3
50
+ <% end %>
51
+ n4
52
+ <%= f.inputs([:first, :last], :legend=>'Foo') %>
53
+ n5
54
+ END
55
+ erb <<END
56
+ 0
57
+ <% form([:foo, :bar], :action=>'/baz') do |f| %>
58
+ 1
59
+ <%= f.tag(:p, {}, 'FBB') %>
60
+ 2
61
+ <%= erb(@nest, :locals=>{:f=>f}) %>
62
+ 3
63
+ <% end %>
64
+ 4
65
+ END
66
+ end
67
+
68
+ r.get 'nest_seq' do
69
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
70
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
71
+ @nest = <<END
72
+ n1
73
+ <% f.subform(:artist) do %>
74
+ n2
75
+ <%= f.input(:name2) %>
76
+ n3
77
+ <% end %>
78
+ n4
79
+ <%= f.subform(:artist, :inputs=>[:name3], :legend=>'Bar') %>
80
+ n5
81
+ END
82
+ erb <<END
83
+ 0
84
+ <% form(@album, :action=>'/baz') do |f| %>
85
+ 1
86
+ <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo') %>
87
+ 2
88
+ <%= erb(@nest, :locals=>{:f=>f}) %>
89
+ 3
90
+ <% end %>
91
+ 4
92
+ END
93
+ end
94
+
95
+ r.get 'hash' do
96
+ erb "<% form({:action=>'/baz'}, :obj=>[:foo]) do |f| %> <%= f.input(:first) %> <% end %>"
97
+ end
98
+
99
+ r.get 'legend' do
100
+ erb <<END
101
+ <% form([:foo, :bar], :action=>'/baz') do |f| %>
102
+ <p>FBB</p>
103
+ <%= f.inputs([:first, :last], :legend=>'Foo') %>
104
+ <p>FBB2</p>
105
+ <% end %>
106
+ END
107
+ end
108
+
109
+ r.get 'combined' do
110
+ erb <<END
111
+ <% form([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') do |f| %>
112
+ <p>FBB</p>
113
+ <%= f.input(:last) %>
114
+ <% end %>
115
+ END
116
+ end
117
+
118
+ r.get 'noblock' do
119
+ erb "<%= form([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') %>"
120
+ end
121
+
122
+ r.get 'noblock_empty' do
123
+ erb "<%= form(:action=>'/baz') %>"
124
+ end
125
+ end
126
+
127
+ shared_examples_for "erb integration" do
128
+ before do
129
+ o = Object.new
130
+ def o.puts(*) end
131
+ @rack = {'rack.input'=>'', 'REQUEST_METHOD'=>'GET', 'rack.errors'=>o, 'SCRIPT_NAME'=>''}
132
+ end
133
+
134
+ specify "#form should add start and end tags and yield Forme::Form instance" do
135
+ sin_get('/').should == '<form action="/baz"> <p>FBB</p> <input id="first" name="first" type="text" value="foo"/> <input id="last" name="last" type="text" value="bar"/> <input type="submit" value="Save"/> </form>'
136
+ end
137
+
138
+ specify "#form should have inputs work with a block" do
139
+ sin_get('/inputs_block').should == '<form action="/baz"><fieldset class="inputs"><legend>FBB</legend> <input id="last" name="last" type="text" value="bar"/> </fieldset></form>'
140
+ end
141
+
142
+ specify "#form should have inputs with fieldset_ol wrapper work with block" do
143
+ sin_get('/inputs_block_wrapper').should == '<form action="/baz"><fieldset class="inputs"><legend>FBB</legend><ol> <input id="last" name="last" type="text" value="bar"/> </ol></fieldset></form>'
144
+ end
145
+
146
+ specify "#form should add start and end tags and yield Forme::Form instance" do
147
+ sin_get('/nest').should == '<form action="/baz"> <p>FBB</p> <div> <input id="first" name="first" type="text" value="foo"/> <input id="last" name="last" type="text" value="bar"/> </div> </form>'
148
+ end
149
+
150
+ specify "#form should correctly handle situation where multiple templates are used with same form object" do
151
+ sin_get('/nest_sep').should == "0 <form action=\"/baz\"> 1 <p>FBB</p> 2 n1 <div> n2 <input id=\"first\" name=\"first\" type=\"text\" value=\"foo\"/> <input id=\"last\" name=\"last\" type=\"text\" value=\"bar\"/> n3 </div> n4 <fieldset class=\"inputs\"><legend>Foo</legend><input id=\"first\" name=\"first\" type=\"text\" value=\"foo\"/><input id=\"last\" name=\"last\" type=\"text\" value=\"bar\"/></fieldset> n5 3 </form>4"
152
+ end
153
+
154
+ specify "#form should correctly handle situation Sequel integration with subforms where multiple templates are used with same form object" do
155
+ sin_get('/nest_seq').sub(%r{<input name=\"_csrf\" type=\"hidden\" value=\"([^\"]+)\"/>}, "<input name=\"_csrf\" type=\"hidden\" value=\"csrf\"/>").should == "0 <form action=\"/baz\" class=\"forme album\" method=\"post\"><input name=\"_csrf\" type=\"hidden\" value=\"csrf\"/> 1 <input id=\"album_artist_attributes_id\" name=\"album[artist_attributes][id]\" type=\"hidden\" value=\"2\"/><fieldset class=\"inputs\"><legend>Foo</legend><label>Name: <input id=\"album_artist_attributes_name\" name=\"album[artist_attributes][name]\" type=\"text\" value=\"A\"/></label></fieldset> 2 n1 <input id=\"album_artist_attributes_id\" name=\"album[artist_attributes][id]\" type=\"hidden\" value=\"2\"/><fieldset class=\"inputs\"><legend>Artist</legend> n2 <label>Name2: <input id=\"album_artist_attributes_name2\" name=\"album[artist_attributes][name2]\" type=\"text\" value=\"A2\"/></label> n3 </fieldset> n4 <input id=\"album_artist_attributes_id\" name=\"album[artist_attributes][id]\" type=\"hidden\" value=\"2\"/><fieldset class=\"inputs\"><legend>Bar</legend><label>Name3: <input id=\"album_artist_attributes_name3\" name=\"album[artist_attributes][name3]\" type=\"text\" value=\"A3\"/></label></fieldset> n5 3 </form>4"
156
+ end
157
+
158
+ specify "#form should accept two hashes instead of requiring obj as first argument" do
159
+ sin_get('/hash').should == '<form action="/baz"> <input id="first" name="first" type="text" value="foo"/> </form>'
160
+ end
161
+
162
+ specify "#form should deal with emitted code" do
163
+ sin_get('/legend').should == '<form action="/baz"> <p>FBB</p> <fieldset class="inputs"><legend>Foo</legend><input id="first" name="first" type="text" value="foo"/><input id="last" name="last" type="text" value="bar"/></fieldset> <p>FBB2</p> </form>'
164
+ end
165
+
166
+ specify "#form should work with :inputs, :button, and :legend options" do
167
+ sin_get('/combined').should == '<form action="/baz"><fieldset class="inputs"><legend>123</legend><input id="first" name="first" type="text" value="foo"/></fieldset> <p>FBB</p> <input id="last" name="last" type="text" value="bar"/> <input type="submit" value="xyz"/></form>'
168
+ end
169
+
170
+ specify "#form should work without a block" do
171
+ sin_get('/noblock').should == '<form action="/baz"><fieldset class="inputs"><legend>123</legend><input id="first" name="first" type="text" value="foo"/></fieldset><input type="submit" value="xyz"/></form>'
172
+ end
173
+
174
+ specify "#form with an empty form should work" do
175
+ sin_get('/noblock_empty').should == '<form action="/baz"></form>'
176
+ end
177
+ end
@@ -2,7 +2,11 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
2
  require File.join(File.dirname(File.expand_path(__FILE__)), 'sequel_helper.rb')
3
3
 
4
4
  require 'rubygems'
5
+ begin
5
6
  require 'action_controller/railtie'
7
+ rescue LoadError
8
+ warn "unable to load rails, skipping rails spec"
9
+ else
6
10
  require 'forme/rails'
7
11
 
8
12
  class FormeRails < Rails::Application
@@ -233,3 +237,4 @@ describe "Forme Rails integration" do
233
237
  sin_get('/safe_buffer').should == '<form action="/baz"><fieldset class="inputs"><legend><b>foo</b></legend><input id="first" name="first" type="text" value="foo"/></fieldset><input type="submit" value="xyz"/></form>'
234
238
  end
235
239
  end
240
+ end
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'sequel_helper.rb')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'erb_helper.rb')
4
+
5
+ require 'rubygems'
6
+ begin
7
+ require 'roda'
8
+ require(ENV['ERUBIS'] ? 'erubis' : 'erb')
9
+ require 'rack/csrf'
10
+ rescue LoadError
11
+ warn "unable to load roda or rack/csrf, skipping roda spec"
12
+ else
13
+ class FormeRodaTest < Roda
14
+ plugin :forme
15
+ use Rack::Session::Cookie, :secret => "__a_very_long_string__"
16
+ use Rack::Csrf
17
+
18
+ def erb(s, opts={})
19
+ render(opts.merge(:inline=>s))
20
+ end
21
+
22
+ route do |r|
23
+ instance_exec(r, &ERB_BLOCK)
24
+ end
25
+ end
26
+
27
+ describe "Forme Roda ERB integration" do
28
+ def sin_get(path)
29
+ s = ''
30
+ FormeRodaTest.app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
31
+ s.gsub(/\s+/, ' ').strip
32
+ end
33
+
34
+ it_should_behave_like "erb integration"
35
+ end
36
+ end
@@ -1,12 +1,16 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
2
  require File.join(File.dirname(File.expand_path(__FILE__)), 'sequel_helper.rb')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'erb_helper.rb')
3
4
 
4
5
  require 'rubygems'
6
+ begin
5
7
  require 'sinatra/base'
6
- require 'forme/sinatra'
7
8
  require(ENV['ERUBIS'] ? 'erubis' : 'erb')
8
9
  require 'rack/csrf'
9
-
10
+ rescue LoadError
11
+ warn "unable to load sinatra or rack/csrf, skipping sinatra spec"
12
+ else
13
+ require 'forme/sinatra'
10
14
  class FormeSinatraTest < Sinatra::Base
11
15
  helpers(Forme::Sinatra::ERB)
12
16
  disable :show_exceptions
@@ -14,129 +18,11 @@ class FormeSinatraTest < Sinatra::Base
14
18
  enable :sessions
15
19
  use Rack::Csrf
16
20
 
17
- get '/' do
18
- erb <<END
19
- <% form([:foo, :bar], :action=>'/baz') do |f| %>
20
- <p>FBB</p>
21
- <%= f.input(:first) %>
22
- <%= f.input(:last) %>
23
- <%= f.button('Save') %>
24
- <% end %>
25
- END
26
- end
27
-
28
- get '/inputs_block' do
29
- erb <<END
30
- <% form([:foo, :bar], :action=>'/baz') do |f| %><% f.inputs(:legend=>'FBB') do %>
31
- <%= f.input(:last) %>
32
- <% end %><% end %>
33
- END
34
- end
35
-
36
- get '/inputs_block_wrapper' do
37
- erb <<END
38
- <% form([:foo, :bar], {:action=>'/baz'}, :inputs_wrapper=>:fieldset_ol) do |f| %><% f.inputs(:legend=>'FBB') do %>
39
- <%= f.input(:last) %>
40
- <% end %><% end %>
41
- END
42
- end
43
-
44
- get '/nest' do
45
- erb <<END
46
- <% form([:foo, :bar], :action=>'/baz') do |f| %>
47
- <%= f.tag(:p, {}, 'FBB') %>
48
- <% f.tag(:div) do %>
49
- <%= f.input(:first) %>
50
- <%= f.input(:last) %>
51
- <% end %>
52
-
53
- <% end %>
54
- END
55
- end
56
-
57
- get '/nest_sep' do
58
- @nest = <<END
59
- n1
60
- <% f.tag(:div) do %>
61
- n2
62
- <%= f.input(:first) %>
63
- <%= f.input(:last) %>
64
- n3
65
- <% end %>
66
- n4
67
- <%= f.inputs([:first, :last], :legend=>'Foo') %>
68
- n5
69
- END
70
- erb <<END
71
- 0
72
- <% form([:foo, :bar], :action=>'/baz') do |f| %>
73
- 1
74
- <%= f.tag(:p, {}, 'FBB') %>
75
- 2
76
- <%= erb(@nest, :locals=>{:f=>f}) %>
77
- 3
78
- <% end %>
79
- 4
80
- END
21
+ def self.get(path, &block)
22
+ super("/#{path}", &block)
81
23
  end
82
24
 
83
- get '/nest_seq' do
84
- @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
85
- @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
86
- @nest = <<END
87
- n1
88
- <% f.subform(:artist) do %>
89
- n2
90
- <%= f.input(:name2) %>
91
- n3
92
- <% end %>
93
- n4
94
- <%= f.subform(:artist, :inputs=>[:name3], :legend=>'Bar') %>
95
- n5
96
- END
97
- erb <<END
98
- 0
99
- <% form(@album, :action=>'/baz') do |f| %>
100
- 1
101
- <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo') %>
102
- 2
103
- <%= erb(@nest, :locals=>{:f=>f}) %>
104
- 3
105
- <% end %>
106
- 4
107
- END
108
- end
109
-
110
- get '/hash' do
111
- erb "<% form({:action=>'/baz'}, :obj=>[:foo]) do |f| %> <%= f.input(:first) %> <% end %>"
112
- end
113
-
114
- get '/legend' do
115
- erb <<END
116
- <% form([:foo, :bar], :action=>'/baz') do |f| %>
117
- <p>FBB</p>
118
- <%= f.inputs([:first, :last], :legend=>'Foo') %>
119
- <p>FBB2</p>
120
- <% end %>
121
- END
122
- end
123
-
124
- get '/combined' do
125
- erb <<END
126
- <% form([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') do |f| %>
127
- <p>FBB</p>
128
- <%= f.input(:last) %>
129
- <% end %>
130
- END
131
- end
132
-
133
- get '/noblock' do
134
- erb "<%= form([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') %>"
135
- end
136
-
137
- get '/noblock_empty' do
138
- erb "<%= form(:action=>'/baz') %>"
139
- end
25
+ instance_exec(self, &ERB_BLOCK)
140
26
  end
141
27
 
142
28
  describe "Forme Sinatra ERB integration" do
@@ -145,53 +31,7 @@ describe "Forme Sinatra ERB integration" do
145
31
  FormeSinatraTest.new.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
146
32
  s.gsub(/\s+/, ' ').strip
147
33
  end
148
- before do
149
- o = Object.new
150
- def o.puts(*) end
151
- @rack = {'rack.input'=>'', 'REQUEST_METHOD'=>'GET', 'rack.errors'=>o}
152
- end
153
-
154
- specify "#form should add start and end tags and yield Forme::Form instance" do
155
- sin_get('/').should == '<form action="/baz"> <p>FBB</p> <input id="first" name="first" type="text" value="foo"/> <input id="last" name="last" type="text" value="bar"/> <input type="submit" value="Save"/> </form>'
156
- end
157
-
158
- specify "#form should have inputs work with a block" do
159
- sin_get('/inputs_block').should == '<form action="/baz"><fieldset class="inputs"><legend>FBB</legend> <input id="last" name="last" type="text" value="bar"/> </fieldset></form>'
160
- end
161
-
162
- specify "#form should have inputs with fieldset_ol wrapper work with block" do
163
- sin_get('/inputs_block_wrapper').should == '<form action="/baz"><fieldset class="inputs"><legend>FBB</legend><ol> <input id="last" name="last" type="text" value="bar"/> </ol></fieldset></form>'
164
- end
165
-
166
- specify "#form should add start and end tags and yield Forme::Form instance" do
167
- sin_get('/nest').should == '<form action="/baz"> <p>FBB</p> <div> <input id="first" name="first" type="text" value="foo"/> <input id="last" name="last" type="text" value="bar"/> </div> </form>'
168
- end
169
34
 
170
- specify "#form should correctly handle situation where multiple templates are used with same form object" do
171
- sin_get('/nest_sep').should == "0 <form action=\"/baz\"> 1 <p>FBB</p> 2 n1 <div> n2 <input id=\"first\" name=\"first\" type=\"text\" value=\"foo\"/> <input id=\"last\" name=\"last\" type=\"text\" value=\"bar\"/> n3 </div> n4 <fieldset class=\"inputs\"><legend>Foo</legend><input id=\"first\" name=\"first\" type=\"text\" value=\"foo\"/><input id=\"last\" name=\"last\" type=\"text\" value=\"bar\"/></fieldset> n5 3 </form>4"
172
- end
173
-
174
- specify "#form should correctly handle situation Sequel integration with subforms where multiple templates are used with same form object" do
175
- sin_get('/nest_seq').sub(%r{<input name=\"_csrf\" type=\"hidden\" value=\"([^\"]+)\"/>}, "<input name=\"_csrf\" type=\"hidden\" value=\"csrf\"/>").should == "0 <form action=\"/baz\" class=\"forme album\" method=\"post\"><input name=\"_csrf\" type=\"hidden\" value=\"csrf\"/> 1 <input id=\"album_artist_attributes_id\" name=\"album[artist_attributes][id]\" type=\"hidden\" value=\"2\"/><fieldset class=\"inputs\"><legend>Foo</legend><label>Name: <input id=\"album_artist_attributes_name\" name=\"album[artist_attributes][name]\" type=\"text\" value=\"A\"/></label></fieldset> 2 n1 <input id=\"album_artist_attributes_id\" name=\"album[artist_attributes][id]\" type=\"hidden\" value=\"2\"/><fieldset class=\"inputs\"><legend>Artist</legend> n2 <label>Name2: <input id=\"album_artist_attributes_name2\" name=\"album[artist_attributes][name2]\" type=\"text\" value=\"A2\"/></label> n3 </fieldset> n4 <input id=\"album_artist_attributes_id\" name=\"album[artist_attributes][id]\" type=\"hidden\" value=\"2\"/><fieldset class=\"inputs\"><legend>Bar</legend><label>Name3: <input id=\"album_artist_attributes_name3\" name=\"album[artist_attributes][name3]\" type=\"text\" value=\"A3\"/></label></fieldset> n5 3 </form>4"
176
- end
177
-
178
- specify "#form should accept two hashes instead of requiring obj as first argument" do
179
- sin_get('/hash').should == '<form action="/baz"> <input id="first" name="first" type="text" value="foo"/> </form>'
180
- end
181
-
182
- specify "#form should deal with emitted code" do
183
- sin_get('/legend').should == '<form action="/baz"> <p>FBB</p> <fieldset class="inputs"><legend>Foo</legend><input id="first" name="first" type="text" value="foo"/><input id="last" name="last" type="text" value="bar"/></fieldset> <p>FBB2</p> </form>'
184
- end
185
-
186
- specify "#form should work with :inputs, :button, and :legend options" do
187
- sin_get('/combined').should == '<form action="/baz"><fieldset class="inputs"><legend>123</legend><input id="first" name="first" type="text" value="foo"/></fieldset> <p>FBB</p> <input id="last" name="last" type="text" value="bar"/> <input type="submit" value="xyz"/></form>'
188
- end
189
-
190
- specify "#form should work without a block" do
191
- sin_get('/noblock').should == '<form action="/baz"><fieldset class="inputs"><legend>123</legend><input id="first" name="first" type="text" value="foo"/></fieldset><input type="submit" value="xyz"/></form>'
192
- end
193
-
194
- specify "#form with an empty form should work" do
195
- sin_get('/noblock_empty').should == '<form action="/baz"></form>'
196
- end
35
+ it_should_behave_like "erb integration"
36
+ end
197
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-01 00:00:00.000000000 Z
11
+ date: 2014-07-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Forme is a forms library with the following goals:
@@ -30,13 +30,17 @@ files:
30
30
  - README.rdoc
31
31
  - Rakefile
32
32
  - lib/forme.rb
33
+ - lib/forme/erb.rb
33
34
  - lib/forme/rails.rb
34
35
  - lib/forme/sinatra.rb
35
36
  - lib/forme/version.rb
37
+ - lib/roda/plugins/forme.rb
36
38
  - lib/sequel/plugins/forme.rb
39
+ - spec/erb_helper.rb
37
40
  - spec/forme_coverage.rb
38
41
  - spec/forme_spec.rb
39
42
  - spec/rails_integration_spec.rb
43
+ - spec/roda_integration_spec.rb
40
44
  - spec/sequel_helper.rb
41
45
  - spec/sequel_plugin_spec.rb
42
46
  - spec/sinatra_integration_spec.rb