forme 0.7.0 → 0.8.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 06d7e50cfae657572071affb86ef307636c65345
4
+ data.tar.gz: 5eef25b91f833f3a57caef3903d25886cb48f00d
5
+ SHA512:
6
+ metadata.gz: a19e5579fc8f0bfe11c5136f2ecc69db057a23f76d08bc01aad4680c1ebeb9fbd27476a04d60265efe5de1d1e5ab0b16dd615f8bc0081c7b733ef9f188e31581
7
+ data.tar.gz: ba0fe6ba4e18fe182c0a93eb9b33f28e0d0f30729ec537f2a3b468d8b9db56a75d657aadb17b4c164a3128d901017d7460a7ce8ecd9bd8a923d5017bc1e4d051
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ === 0.8.0 (2013-10-30)
2
+
3
+ * form calls without block or :inputs or :button options are now handled correctly in the Sinatra integration (jeremyevans)
4
+
5
+ * CSRF token tags are now automatically added to forms in Rails and Sinatra if using rack_csrf (jeremyevans) (#5)
6
+
7
+ * Form objects now support a :hidden_tags option for automatically adding hidden tags (jeremyevans)
8
+
9
+ * Sequel many_to_one associations with existing and required values no longer have a blank option added by default (jeremyevans)
10
+
11
+ * ActiveSupport::SafeBuffer objects are now automatically treated as raw in the Rails integration (jeremyevans)
12
+
1
13
  === 0.7.0 (2012-05-02)
2
14
 
3
15
  * Support :label_position option in both of the labelers, can be set to :before or :after to override the default (jeremyevans)
data/README.rdoc CHANGED
@@ -76,7 +76,7 @@ You can even do everything in a single method call:
76
76
 
77
77
  = Basic Design
78
78
 
79
- Interally, Forme builds an abstract syntax tree of objects that
79
+ Internally, Forme builds an abstract syntax tree of objects that
80
80
  represent the form. The abstract syntax tree goes through a
81
81
  series of transformations that convert it from high level
82
82
  abstract forms to low level abstract forms and finally to
data/lib/forme.rb CHANGED
@@ -99,7 +99,7 @@ module Forme
99
99
  # +obj+ or +block+, but not both. If +obj+ is given, should be
100
100
  # either a +Class+ instance or it should respond to +call+. If a
101
101
  # +Class+ instance is given, instances of that class should respond
102
- # to +call+, and the a new instance of that class should be used
102
+ # to +call+, and a new instance of that class should be used
103
103
  # for each transformation.
104
104
  def self.register_transformer(type, sym, obj=nil, &block)
105
105
  raise Error, "Not a valid transformer type" unless TRANSFORMERS.has_key?(type)
@@ -145,6 +145,7 @@ module Forme
145
145
  # :obj :: Sets the +obj+ attribute
146
146
  # :error_handler :: Sets the +error_handler+ for the form
147
147
  # :formatter :: Sets the +formatter+ for the form
148
+ # :hidden_tags :: Sets the hidden tags to automatically add to this form.
148
149
  # :inputs_wrapper :: Sets the +inputs_wrapper+ for the form
149
150
  # :labeler :: Sets the +labeler+ for the form
150
151
  # :wrapper :: Sets the +wrapper+ for the form
@@ -175,6 +176,15 @@ module Forme
175
176
  # Must respond to +call+ or be a registered symbol.
176
177
  attr_reader :serializer
177
178
 
179
+ # The hidden tags to automatically add to the form. If set, this should be an
180
+ # array, where elements are one of the following types:
181
+ # String, Array, Forme::Tag :: Added directly as a child of the form tag.
182
+ # Hash :: Adds a hidden tag for each entry, with keys as the name of the hidden
183
+ # tag and values as the value of the hidden tag.
184
+ # Proc :: Will be called with the form tag object, and should return an instance
185
+ # of one of the handled types (or nil to not add a tag).
186
+ attr_reader :hidden_tags
187
+
178
188
  # Create a +Form+ instance and yield it to the block,
179
189
  # injecting the opening form tag before yielding and
180
190
  # the closing form tag after yielding.
@@ -232,6 +242,7 @@ module Forme
232
242
  end
233
243
  config = CONFIGURATIONS[@opts[:config]||Forme.default_config]
234
244
  TRANSFORMER_TYPES.each{|k| instance_variable_set(:"@#{k}", transformer(k, @opts.fetch(k, config[k])))}
245
+ @hidden_tags = @opts[:hidden_tags]
235
246
  @nesting = []
236
247
  end
237
248
 
@@ -285,7 +296,7 @@ module Forme
285
296
 
286
297
  # Create a form tag with the given attributes.
287
298
  def form(attr={}, &block)
288
- tag(:form, attr, &block)
299
+ tag(:form, attr, method(:hidden_form_tags), &block)
289
300
  end
290
301
 
291
302
  # Formats the +input+ using the +formatter+.
@@ -429,6 +440,35 @@ module Forme
429
440
 
430
441
  private
431
442
 
443
+ # Return array of hidden tags to use for this form,
444
+ # or nil if the form does not have hidden tags added automatically.
445
+ def hidden_form_tags(form_tag)
446
+ if hidden_tags
447
+ tags = []
448
+ hidden_tags.each do |hidden_tag|
449
+ hidden_tag = hidden_tag.call(form_tag) if hidden_tag.respond_to?(:call)
450
+ tags.concat(parse_hidden_tags(hidden_tag))
451
+ end
452
+ tags
453
+ end
454
+ end
455
+
456
+ # Handle various types of hidden tags for the form.
457
+ def parse_hidden_tags(hidden_tag)
458
+ case hidden_tag
459
+ when Array
460
+ hidden_tag
461
+ when Tag, String
462
+ [hidden_tag]
463
+ when Hash
464
+ hidden_tag.map{|k,v| _tag(:input, :type=>:hidden, :name=>k, :value=>v)}
465
+ when nil
466
+ []
467
+ else
468
+ raise Error, "unhandled hidden_tag response: #{hidden_tag.inspect}"
469
+ end
470
+ end
471
+
432
472
  # Extend +obj+ with +Serialized+ and associate it with the receiver, such
433
473
  # that calling +to_s+ on the object will use the receiver's serializer
434
474
  # to generate the resulting string.
@@ -530,15 +570,8 @@ module Forme
530
570
 
531
571
  # Set the +form+, +type+, +attr+, and +children+.
532
572
  def initialize(form, type, attr={}, children=nil)
533
- case children
534
- when Array
535
- @children = children
536
- when nil
537
- @children = nil
538
- else
539
- @children = [children]
540
- end
541
573
  @form, @type, @attr = form, type, (attr||{})
574
+ @children = parse_children(children)
542
575
  end
543
576
 
544
577
  # Adds a child to the array of receiver's children.
@@ -560,6 +593,22 @@ module Forme
560
593
  def to_s
561
594
  form.serialize(self)
562
595
  end
596
+
597
+ private
598
+
599
+ # Convert children constructor argument into the children to use for the tag.
600
+ def parse_children(children)
601
+ case children
602
+ when Array
603
+ children
604
+ when Proc, Method
605
+ parse_children(children.call(self))
606
+ when nil
607
+ nil
608
+ else
609
+ [children]
610
+ end
611
+ end
563
612
  end
564
613
 
565
614
  # Module that can extend objects associating them with a specific
data/lib/forme/rails.rb CHANGED
@@ -1,7 +1,28 @@
1
1
  require 'forme'
2
2
 
3
+ class ActiveSupport::SafeBuffer
4
+ include Forme::Raw
5
+ end
6
+
3
7
  module Forme
4
- module Rails # :nodoc:
8
+ module Rails
9
+ HIDDEN_TAGS = []
10
+
11
+ # Add a hidden tag proc that will be used for all forms created via Forme::Rails::ERB#form.
12
+ # The block is yielded the Forme::Tag object for the form tag.
13
+ # The block should return either nil if hidden tag should be added, or a Forme::Tag object (or an array of them),
14
+ # or a hash with keys specifying the name of the tags and the values specifying the values of the tags .
15
+ def self.add_hidden_tag(&block)
16
+ HIDDEN_TAGS << block
17
+ end
18
+
19
+ # Add CSRF token tag by default for POST forms
20
+ add_hidden_tag do |tag|
21
+ if (form = tag.form) && (template = form.template) && template.protect_against_forgery? && tag.attr[:method].to_s.upcase == 'POST'
22
+ {template.request_forgery_protection_token=>template.form_authenticity_token}
23
+ end
24
+ end
25
+
5
26
  # Subclass used when using Forme/Rails ERB integration,
6
27
  # handling integration with the view template.
7
28
  class Form < ::Forme::Form
@@ -66,7 +87,7 @@ module Forme
66
87
  def tag_(type, attr={}, children=[])
67
88
  tag = _tag(type, attr, children)
68
89
  emit(serializer.serialize_open(tag)) if serializer.respond_to?(:serialize_open)
69
- Array(children).each{|c| emit(c)}
90
+ Array(tag.children).each{|c| emit(c)}
70
91
  yield self if block_given?
71
92
  emit(serializer.serialize_close(tag)) if serializer.respond_to?(:serialize_close)
72
93
  end
@@ -90,7 +111,7 @@ module Forme
90
111
  # opening attributes, third if provided is
91
112
  # +Form+'s options.
92
113
  def forme(obj=nil, attr={}, opts={}, &block)
93
- h = {:template=>self}
114
+ h = {:template=>self, :hidden_tags=>Forme::Rails::HIDDEN_TAGS}
94
115
  (obj.is_a?(Hash) ? attr = attr.merge(h) : opts = opts.merge(h))
95
116
  Form.form(obj, attr, opts, &block)
96
117
  end
data/lib/forme/sinatra.rb CHANGED
@@ -1,7 +1,24 @@
1
1
  require 'forme'
2
2
 
3
3
  module Forme
4
- module Sinatra # :nodoc:
4
+ 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
+
5
22
  # Subclass used when using Forme/Sinatra ERB integration.
6
23
  # Handles integrating into the view template so that
7
24
  # methods with blocks can inject strings into the output.
@@ -37,7 +54,7 @@ module Forme
37
54
  if block
38
55
  capture(block){super}
39
56
  else
40
- capture{super}
57
+ super
41
58
  end
42
59
  end
43
60
 
@@ -50,7 +67,7 @@ module Forme
50
67
  if block
51
68
  capture(block) do
52
69
  emit(serializer.serialize_open(tag)) if serializer.respond_to?(:serialize_open)
53
- children.each{|c| emit(c)}
70
+ Array(tag.children).each{|c| emit(c)}
54
71
  yield self
55
72
  emit(serializer.serialize_close(tag)) if serializer.respond_to?(:serialize_close)
56
73
  end
@@ -92,7 +109,7 @@ module Forme
92
109
  # +Form+'s options.
93
110
  def form(obj=nil, attr={}, opts={}, &block)
94
111
  if block
95
- h = {:output=>@_out_buf}
112
+ h = {:output=>@_out_buf, :hidden_tags=>Forme::Sinatra::HIDDEN_TAGS, :env=>env}
96
113
  (obj.is_a?(Hash) ? attr = attr.merge(h) : opts = opts.merge(h))
97
114
  Form.form(obj, attr, opts, &block)
98
115
  else
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.7.0'.freeze
3
+ VERSION = '0.8.0'.freeze
4
4
 
5
5
  # Returns the version as a frozen string (e.g. '0.1.0')
6
6
  def self.version
@@ -309,8 +309,8 @@ module Sequel # :nodoc:
309
309
  wrapper ? wrapper.call(radios, _input(:radio, opts)) : radios
310
310
  else
311
311
  opts[:id] = form.namespaced_id(key) unless opts.has_key?(:id)
312
- opts[:add_blank] = true if !opts.has_key?(:add_blank)
313
312
  opts[:required] = true if !opts.has_key?(:required) && (sch = obj.model.db_schema[key]) && !sch[:allow_null]
313
+ opts[:add_blank] = true if !opts.has_key?(:add_blank) && !(opts[:required] && opts[:value])
314
314
  handle_label(field)
315
315
  ::Forme.attr_classes(opts[:wrapper_attr], "required") if opts[:required]
316
316
  _input(:select, opts)
data/spec/forme_spec.rb CHANGED
@@ -246,6 +246,16 @@ describe "Forme plain forms" do
246
246
  @f.tag(:textarea, {:name=>:foo}, :bar).to_s.should == '<textarea name="foo">bar</textarea>'
247
247
  end
248
248
 
249
+ specify "#tag should accept children as procs" do
250
+ @f.tag(:div, {:class=>"foo"}, lambda{|t| t.form.tag(:input, :class=>t.attr[:class])}).to_s.should == '<div class="foo"><input class="foo"/></div>'
251
+ end
252
+
253
+ specify "#tag should accept children as methods" do
254
+ o = Object.new
255
+ def o.foo(t) t.form.tag(:input, :class=>t.attr[:class]) end
256
+ @f.tag(:div, {:class=>"foo"}, o.method(:foo)).to_s.should == '<div class="foo"><input class="foo"/></div>'
257
+ end
258
+
249
259
  specify "should have an #inputs method for multiple inputs wrapped in a fieldset" do
250
260
  @f.inputs([:textarea, :text]).to_s.should == '<fieldset class="inputs"><textarea></textarea><input type="text"/></fieldset>'
251
261
  end
@@ -325,6 +335,10 @@ describe "Forme plain forms" do
325
335
  @f.input(:checkbox, :labeler=>:explicit, :label=>'Foo', :value=>'foo', :name=>'a', :id=>'bar', :label_position=>:before).to_s.should == '<label for="bar">Foo</label><input id="bar_hidden" name="a" type="hidden" value="0"/><input id="bar" name="a" type="checkbox" value="foo"/>'
326
336
  end
327
337
 
338
+ specify "inputs handle implicit labels or checkboxes without hidden fields with :label_position=>:before" do
339
+ @f.input(:checkbox, :label=>'Foo', :value=>'foo', :name=>'a', :id=>'bar', :label_position=>:before, :no_hidden=>true).to_s.should == '<label>Foo <input id="bar" name="a" type="checkbox" value="foo"/></label>'
340
+ end
341
+
328
342
  specify "inputs should accept a :error_handler option to use a custom error_handler" do
329
343
  @f.input(:textarea, :error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}, :error=>'bar', :id=>:foo).to_s.should == '<textarea class="error" id="foo"></textarea>!!! bar'
330
344
  end
@@ -360,6 +374,36 @@ describe "Forme plain forms" do
360
374
  end
361
375
  end
362
376
 
377
+ describe "Forme::Form :hidden_tags option " do
378
+ before do
379
+ @f = Forme::Form.new
380
+ end
381
+
382
+ specify "should handle hash" do
383
+ Forme.form({}, :hidden_tags=>[{:a=>'b'}]).to_s.should == '<form><input name="a" type="hidden" value="b"/></form>'
384
+ end
385
+
386
+ specify "should handle array" do
387
+ Forme.form({}, :hidden_tags=>[["a ", "b"]]).to_s.should == '<form>a b</form>'
388
+ end
389
+
390
+ specify "should handle string" do
391
+ Forme.form({}, :hidden_tags=>["a "]).to_s.should == '<form>a </form>'
392
+ end
393
+
394
+ specify "should handle proc return hash" do
395
+ Forme.form({}, :hidden_tags=>[lambda{|tag| {:a=>'b'}}]).to_s.should == '<form><input name="a" type="hidden" value="b"/></form>'
396
+ end
397
+
398
+ specify "should handle proc return tag" do
399
+ Forme.form({:method=>'post'}, :hidden_tags=>[lambda{|tag| tag.form._tag(tag.attr[:method])}]).to_s.should == '<form method="post"><post></post></form>'
400
+ end
401
+
402
+ specify "should raise error for unhandled object" do
403
+ proc{Forme.form({}, :hidden_tags=>[Object.new])}.should raise_error
404
+ end
405
+ end
406
+
363
407
  describe "Forme custom" do
364
408
  specify "formatters can be specified as a proc" do
365
409
  Forme::Form.new(:formatter=>proc{|i| i.form._tag(:textarea, i.opts.map{|k,v| [v.upcase, k.to_s.downcase]})}).input(:text, :name=>'foo').to_s.should == '<textarea FOO="name"></textarea>'
@@ -6,10 +6,12 @@ require 'action_controller/railtie'
6
6
  require 'forme/rails'
7
7
 
8
8
  class FormeRails < Rails::Application
9
- config.secret_token = routes.append { match ':action' , :controller=>'forme' }.inspect
9
+ config.secret_token = routes.append { get ':action' , :controller=>'forme' }.inspect
10
10
  config.active_support.deprecation = :stderr
11
11
  config.middleware.delete(ActionDispatch::ShowExceptions)
12
- config.threadsafe!
12
+ config.middleware.delete("Rack::Lock")
13
+ config.secret_key_base = 'foo'
14
+ config.eager_load = true
13
15
  initialize!
14
16
  end
15
17
 
@@ -139,6 +141,10 @@ END
139
141
  def noblock
140
142
  render :inline => "<%= forme([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') %>"
141
143
  end
144
+
145
+ def safe_buffer
146
+ render :inline => "<%= forme([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'<b>foo</b>'.html_safe) %>"
147
+ end
142
148
  end
143
149
 
144
150
  describe "Forme Rails integration" do
@@ -174,7 +180,7 @@ describe "Forme Rails integration" do
174
180
  end
175
181
 
176
182
  specify "#form should correctly handle situation Sequel integration with subforms where multiple templates are used with same form object" do
177
- sin_get('/nest_seq').should == "0 <form action=\"/baz\" class=\"forme album\" method=\"post\"> 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\"/> n2 <label>Name2: <input id=\"album_artist_attributes_name2\" name=\"album[artist_attributes][name2]\" type=\"text\" value=\"A2\"/></label> n3 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"
183
+ sin_get('/nest_seq').sub(%r{<input name=\"authenticity_token\" type=\"hidden\" value=\"([^\"]+)\"/>}, "<input name=\"authenticity_token\" type=\"hidden\" value=\"csrf\"/>").should == "0 <form action=\"/baz\" class=\"forme album\" method=\"post\"><input name=\"authenticity_token\" 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\"/> n2 <label>Name2: <input id=\"album_artist_attributes_name2\" name=\"album[artist_attributes][name2]\" type=\"text\" value=\"A2\"/></label> n3 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"
178
184
  end
179
185
 
180
186
  specify "#form should accept two hashes instead of requiring obj as first argument" do
@@ -192,4 +198,8 @@ describe "Forme Rails integration" do
192
198
  specify "#form should work without a block" do
193
199
  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>'
194
200
  end
201
+
202
+ specify "#form should handle Rails SafeBuffers" do
203
+ 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>'
204
+ end
195
205
  end
@@ -17,6 +17,13 @@ describe "Forme Sequel::Model forms" do
17
17
  @b.form(:class=>:foo, :method=>:get).to_s.should == '<form class="foo forme album" method="get"></form>'
18
18
  end
19
19
 
20
+ specify "should handle invalid methods" do
21
+ def @ab.db_schema
22
+ super.merge(:foo=>{:type=>:bar})
23
+ end
24
+ @b.input(:foo, :value=>'baz').to_s.should == '<label>Foo: <input id="album_foo" name="album[foo]" type="text" value="baz"/></label>'
25
+ end
26
+
20
27
  specify "should allow an array of classes" do
21
28
  @b.form(:class=>[:foo, :bar]).to_s.should == '<form class="foo bar forme album" method="post"></form>'
22
29
  @b.form(:class=>[:foo, [:bar, :baz]]).to_s.should == '<form class="foo bar baz forme album" method="post"></form>'
@@ -122,12 +129,16 @@ describe "Forme Sequel::Model forms" do
122
129
  @c.input(:artist).to_s.should == '<label>Artist: <select id="album_artist_id" name="album[artist_id]"><option value=""></option><option value="1">a</option><option selected="selected" value="2">d</option></select></label>'
123
130
  end
124
131
 
132
+ specify "should not add a blank option by default if there is a default value and it is required" do
133
+ @b.input(:artist, :required=>true).to_s.should == '<label>Artist<abbr title="required">*</abbr>: <select id="album_artist_id" name="album[artist_id]" required="required"><option selected="selected" value="1">a</option><option value="2">d</option></select></label>'
134
+ end
135
+
125
136
  specify "should allow overriding default input type using a :type option" do
126
137
  @b.input(:artist, :type=>:string, :value=>nil).to_s.should == '<label>Artist: <input id="album_artist" name="album[artist]" type="text"/></label>'
127
138
  end
128
139
 
129
140
  specify "should use a required wrapper tag for many_to_one required associations" do
130
- @b.input(:artist, :required=>true, :wrapper=>:li).to_s.should == '<li class="many_to_one required"><label>Artist<abbr title="required">*</abbr>: <select id="album_artist_id" name="album[artist_id]" required="required"><option value=""></option><option selected="selected" value="1">a</option><option value="2">d</option></select></label></li>'
141
+ @b.input(:artist, :required=>true, :wrapper=>:li).to_s.should == '<li class="many_to_one required"><label>Artist<abbr title="required">*</abbr>: <select id="album_artist_id" name="album[artist_id]" required="required"><option selected="selected" value="1">a</option><option value="2">d</option></select></label></li>'
131
142
  end
132
143
 
133
144
  specify "should use a set of radio buttons for many_to_one associations with :as=>:radio option" do
@@ -5,11 +5,14 @@ require 'rubygems'
5
5
  require 'sinatra/base'
6
6
  require 'forme/sinatra'
7
7
  require(ENV['ERUBIS'] ? 'erubis' : 'erb')
8
+ require 'rack/csrf'
8
9
 
9
10
  class FormeSinatraTest < Sinatra::Base
10
11
  helpers(Forme::Sinatra::ERB)
11
12
  disable :show_exceptions
12
13
  enable :raise_errors
14
+ enable :sessions
15
+ use Rack::Csrf
13
16
 
14
17
  get '/' do
15
18
  erb <<END
@@ -24,21 +27,17 @@ END
24
27
 
25
28
  get '/inputs_block' do
26
29
  erb <<END
27
- <% form([:foo, :bar], :action=>'/baz') do |f| %>
28
- <% f.inputs(:legend=>'FBB') do %>
30
+ <% form([:foo, :bar], :action=>'/baz') do |f| %><% f.inputs(:legend=>'FBB') do %>
29
31
  <%= f.input(:last) %>
30
- <% end %>
31
- <% end %>
32
+ <% end %><% end %>
32
33
  END
33
34
  end
34
35
 
35
36
  get '/inputs_block_wrapper' do
36
37
  erb <<END
37
- <% form([:foo, :bar], {:action=>'/baz'}, :inputs_wrapper=>:fieldset_ol) do |f| %>
38
- <% f.inputs(:legend=>'FBB') do %>
38
+ <% form([:foo, :bar], {:action=>'/baz'}, :inputs_wrapper=>:fieldset_ol) do |f| %><% f.inputs(:legend=>'FBB') do %>
39
39
  <%= f.input(:last) %>
40
- <% end %>
41
- <% end %>
40
+ <% end %><% end %>
42
41
  END
43
42
  end
44
43
 
@@ -134,11 +133,17 @@ END
134
133
  get '/noblock' do
135
134
  erb "<%= form([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') %>"
136
135
  end
136
+
137
+ get '/noblock_empty' do
138
+ erb "<%= form(:action=>'/baz') %>"
139
+ end
137
140
  end
138
141
 
139
142
  describe "Forme Sinatra ERB integration" do
140
143
  def sin_get(path)
141
- FormeSinatraTest.new.call(@rack.merge('PATH_INFO'=>path))[2].join.gsub(/\s+/, ' ').strip
144
+ s = ''
145
+ FormeSinatraTest.new.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
146
+ s.gsub(/\s+/, ' ').strip
142
147
  end
143
148
  before do
144
149
  o = Object.new
@@ -167,7 +172,7 @@ describe "Forme Sinatra ERB integration" do
167
172
  end
168
173
 
169
174
  specify "#form should correctly handle situation Sequel integration with subforms where multiple templates are used with same form object" do
170
- sin_get('/nest_seq').should == "0 <form action=\"/baz\" class=\"forme album\" method=\"post\"> 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\"/> n2 <label>Name2: <input id=\"album_artist_attributes_name2\" name=\"album[artist_attributes][name2]\" type=\"text\" value=\"A2\"/></label> n3 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"
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\"/> n2 <label>Name2: <input id=\"album_artist_attributes_name2\" name=\"album[artist_attributes][name2]\" type=\"text\" value=\"A2\"/></label> n3 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"
171
176
  end
172
177
 
173
178
  specify "#form should accept two hashes instead of requiring obj as first argument" do
@@ -185,4 +190,8 @@ describe "Forme Sinatra ERB integration" do
185
190
  specify "#form should work without a block" do
186
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>'
187
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
188
197
  end
metadata CHANGED
@@ -1,28 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
5
- prerelease:
4
+ version: 0.8.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jeremy Evans
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-05-02 00:00:00.000000000 Z
11
+ date: 2013-10-30 00:00:00.000000000 Z
13
12
  dependencies: []
14
- description: ! 'Forme is a forms library with the following goals:
15
-
13
+ description: |
14
+ Forme is a forms library with the following goals:
16
15
 
17
16
  1) Have no external dependencies
18
-
19
17
  2) Have a simple API
20
-
21
18
  3) Support forms both with and without related objects
22
-
23
19
  4) Allow compiling down to different types of output
24
-
25
- '
26
20
  email: code@jeremyevans.net
27
21
  executables: []
28
22
  extensions: []
@@ -48,33 +42,32 @@ files:
48
42
  - lib/sequel/plugins/forme.rb
49
43
  homepage: http://gihub.com/jeremyevans/forme
50
44
  licenses: []
45
+ metadata: {}
51
46
  post_install_message:
52
47
  rdoc_options:
53
48
  - --quiet
54
49
  - --line-numbers
55
50
  - --inline-source
56
51
  - --title
57
- - ! 'Forme: HTML forms library'
52
+ - 'Forme: HTML forms library'
58
53
  - --main
59
54
  - README.rdoc
60
55
  require_paths:
61
56
  - lib
62
57
  required_ruby_version: !ruby/object:Gem::Requirement
63
- none: false
64
58
  requirements:
65
- - - ! '>='
59
+ - - '>='
66
60
  - !ruby/object:Gem::Version
67
61
  version: '0'
68
62
  required_rubygems_version: !ruby/object:Gem::Requirement
69
- none: false
70
63
  requirements:
71
- - - ! '>='
64
+ - - '>='
72
65
  - !ruby/object:Gem::Version
73
66
  version: '0'
74
67
  requirements: []
75
68
  rubyforge_project:
76
- rubygems_version: 1.8.11
69
+ rubygems_version: 2.0.3
77
70
  signing_key:
78
- specification_version: 3
71
+ specification_version: 4
79
72
  summary: HTML forms library
80
73
  test_files: []