reform 2.0.5 → 2.1.0.rc1

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -1
  3. data/CHANGES.md +12 -0
  4. data/Gemfile +12 -2
  5. data/README.md +9 -14
  6. data/Rakefile +1 -1
  7. data/database.sqlite3 +0 -0
  8. data/lib/reform.rb +1 -0
  9. data/lib/reform/contract.rb +13 -20
  10. data/lib/reform/contract/validate.rb +9 -7
  11. data/lib/reform/form.rb +45 -31
  12. data/lib/reform/form/active_model.rb +10 -10
  13. data/lib/reform/form/active_model/form_builder_methods.rb +5 -4
  14. data/lib/reform/form/active_model/model_reflections.rb +2 -2
  15. data/lib/reform/form/active_model/model_validations.rb +3 -3
  16. data/lib/reform/form/active_model/validations.rb +49 -32
  17. data/lib/reform/form/dry.rb +55 -0
  18. data/lib/reform/form/lotus.rb +4 -1
  19. data/lib/reform/form/module.rb +3 -17
  20. data/lib/reform/form/multi_parameter_attributes.rb +0 -9
  21. data/lib/reform/form/populator.rb +72 -30
  22. data/lib/reform/form/validate.rb +19 -43
  23. data/lib/reform/form/validation/unique_validator.rb +39 -6
  24. data/lib/reform/validation.rb +40 -0
  25. data/lib/reform/validation/groups.rb +73 -0
  26. data/lib/reform/version.rb +1 -1
  27. data/reform.gemspec +3 -1
  28. data/test/active_record_test.rb +2 -0
  29. data/test/contract_test.rb +2 -2
  30. data/test/deprecation_test.rb +27 -0
  31. data/test/deserialize_test.rb +29 -8
  32. data/test/dummy/config/locales/en.yml +4 -1
  33. data/test/errors_test.rb +4 -4
  34. data/test/feature_test.rb +2 -2
  35. data/test/fixtures/dry_error_messages.yml +43 -0
  36. data/test/form_builder_test.rb +10 -8
  37. data/test/form_test.rb +1 -36
  38. data/test/inherit_test.rb +20 -8
  39. data/test/module_test.rb +2 -30
  40. data/test/parse_pipeline_test.rb +15 -0
  41. data/test/populate_test.rb +41 -12
  42. data/test/populator_skip_test.rb +28 -0
  43. data/test/reform_test.rb +1 -1
  44. data/test/skip_if_test.rb +10 -3
  45. data/test/test_helper.rb +11 -2
  46. data/test/unique_test.rb +72 -1
  47. data/test/validate_test.rb +6 -7
  48. data/test/validation/activemodel_validation_test.rb +252 -0
  49. data/test/validation/dry_validation_test.rb +330 -0
  50. metadata +63 -10
  51. data/lib/reform/schema.rb +0 -13
data/test/form_test.rb CHANGED
@@ -31,47 +31,12 @@ class FormTest < MiniTest::Spec
31
31
  form.errors.to_s.must_equal "{:title=>[\"can't be blank\"], :genre=>[\"can't be blank\"], :band=>[\"can't be blank\"]}"
32
32
  end
33
33
 
34
- # ::schema
35
- # TODO: refactor schema tests, this is all covered in Disposable.
36
- describe "::schema" do
37
- let (:schema) { AlbumForm.schema }
38
-
39
- # it must be a clone
40
- it { schema.wont_equal AlbumForm.representer_class }
41
- it { assert schema < Representable::Decorator }
42
- it { schema.representable_attrs.get(:title).name.must_equal "title" }
43
-
44
- # hit is clone.
45
- it { schema.representable_attrs.get(:hit).representer_module.object_id.wont_equal AlbumForm.representer_class.representable_attrs.get(:hit).representer_module.object_id }
46
- it { assert schema.representable_attrs.get(:hit).representer_module < Representable::Decorator }
47
- # we delete :prepare from schema.
48
- it { schema.representable_attrs.get(:hit)[:prepare].must_equal nil }
49
-
50
- # band:label is clone.
51
- # this test might look ridiculous but it is mission-critical to assert that schema is really a clone and doesn't mess up the original structure.
52
- let (:label) { schema.representable_attrs.get(:band).representer_module.representable_attrs.get(:label) }
53
- it { assert label.representer_module < Representable::Decorator }
54
- it { label.representer_module.object_id.wont_equal AlbumForm.representer_class.representable_attrs.get(:band).representer_module.representer_class.representable_attrs.get(:label).representer_module.object_id }
55
-
56
- # #apply
57
- it do
58
- properties = []
59
-
60
- schema.apply do |dfn|
61
- properties << dfn.name
62
- end
63
-
64
- properties.must_equal ["title", "hit", "title", "songs", "title", "band", "label", "name"]
65
- end
66
- end
67
-
68
-
69
34
  describe "::dup" do
70
35
  let (:cloned) { AlbumForm.clone }
71
36
 
72
37
  # #dup is called in Op.inheritable_attr(:contract_class), it must be subclass of the original one.
73
38
  it { cloned.wont_equal AlbumForm }
74
- it { AlbumForm.representer_class.wont_equal cloned.representer_class }
39
+ it { AlbumForm.definitions.wont_equal cloned.definitions }
75
40
 
76
41
  it do
77
42
  # currently, forms need a name for validation, even without AM.
data/test/inherit_test.rb CHANGED
@@ -2,9 +2,10 @@ require 'test_helper'
2
2
  require 'representable/json'
3
3
 
4
4
  class InheritTest < BaseTest
5
+ Populator = Reform::Form::Populator
6
+
5
7
  class AlbumForm < Reform::Form
6
8
  property :title, deserializer: {instance: "Instance"}, skip_if: "skip_if in AlbumForm" # allow direct configuration of :deserializer.
7
- # puts "[#{options_for(:title)[:deserializer].object_id}] ALB@@@@@ #{options_for(:title)[:deserializer].inspect}"
8
9
 
9
10
  property :hit, populator: "Populator" do
10
11
  property :title
@@ -75,28 +76,29 @@ require "pp"
75
76
  AlbumForm.options_for(:title)[:deserializer].object_id.wont_equal CompilationForm.options_for(:title)[:deserializer].object_id
76
77
 
77
78
  # don't overwrite direct deserializer: {} configuration.
78
- AlbumForm.options_for(:title)[:deserializer][:instance].must_equal "Instance"
79
+ AlbumForm.options_for(:title)[:internal_populator].must_be_instance_of Reform::Form::Populator::Sync
79
80
  AlbumForm.options_for(:title)[:deserializer][:skip_parse].must_equal "skip_if in AlbumForm"
80
81
 
81
- AlbumForm.options_for(:hit)[:deserializer][:instance].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
82
+ AlbumForm.options_for(:hit)[:internal_populator].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
82
83
  # AlbumForm.options_for(:hit)[:deserializer][:instance].inspect.must_be_instance_with Reform::Form::Populator, user_proc: "Populator"
83
84
 
84
85
 
85
- AlbumForm.options_for(:songs)[:deserializer][:instance].must_be_instance_of Reform::Form::Populator::IfEmpty
86
+ AlbumForm.options_for(:songs)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
86
87
  AlbumForm.options_for(:songs)[:deserializer][:skip_parse].must_be_instance_of Reform::Form::Validate::Skip::AllBlank
87
88
 
88
- AlbumForm.options_for(:artist)[:deserializer][:instance].must_be_instance_of Reform::Form::Populator::IfEmpty
89
+ AlbumForm.options_for(:artist)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
89
90
 
90
91
 
91
92
 
92
93
  CompilationForm.options_for(:title)[:deserializer][:skip_parse].must_equal "skip_if from CompilationForm"
93
94
  # pp CompilationForm.options_for(:songs)
94
- CompilationForm.options_for(:songs)[:deserializer][:instance].must_be_instance_of Reform::Form::Populator::IfEmpty
95
+ CompilationForm.options_for(:songs)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
96
+
95
97
 
96
- CompilationForm.options_for(:artist)[:deserializer][:instance].must_be_instance_of Reform::Form::Populator::IfEmpty
98
+ CompilationForm.options_for(:artist)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
97
99
 
98
100
  # completely overwrite inherited.
99
- CompilationForm.options_for(:hit)[:deserializer][:instance].must_be_instance_of Reform::Form::Populator::Sync # reset to default.
101
+ CompilationForm.options_for(:hit)[:internal_populator].must_be_instance_of Reform::Form::Populator::Sync # reset to default.
100
102
  CompilationForm.options_for(:hit)[:deserializer][:skip_parse].must_equal "SkipParse"
101
103
 
102
104
 
@@ -104,4 +106,14 @@ require "pp"
104
106
  AlbumForm.new(OpenStruct.new(artist: OpenStruct.new)).artist.artist_id.must_equal 1
105
107
  CompilationForm.new(OpenStruct.new(artist: OpenStruct.new)).artist.artist_id.must_equal 1
106
108
  end
109
+
110
+
111
+ class CDForm < AlbumForm
112
+ # override :artist's original populate_if_empty but with :inherit.
113
+ property :artist, inherit: true, populator: "CD Populator" do
114
+
115
+ end
116
+ end
117
+
118
+ it { CDForm.options_for(:artist)[:internal_populator].instance_variable_get(:@user_proc).must_equal "CD Populator" }
107
119
  end
data/test/module_test.rb CHANGED
@@ -81,50 +81,22 @@ class ModuleInclusionTest < MiniTest::Spec
81
81
 
82
82
  property :name
83
83
  validates :name, :presence => true
84
+
84
85
  end
85
86
 
86
87
  class AlbumForm < Reform::Form
87
88
  include AlbumFormModule
88
89
 
90
+ # pp heritage
89
91
  property :band, :inherit => true do
90
92
  property :label
91
93
  validates :label, :presence => true
92
94
  end
93
95
  end
94
- # puts "......"+ AlbumForm.representer_class.representable_attrs.get(:band).inspect
95
96
 
96
97
  it do
97
98
  form = AlbumForm.new(OpenStruct.new(:band => OpenStruct.new))
98
99
  form.validate({"band" => {}})
99
100
  form.errors.messages.must_equal({:"band.title"=>["can't be blank"], :"band.label"=>["can't be blank"], :name=>["can't be blank"]})
100
101
  end
101
-
102
-
103
- # # including representer into form
104
- # module GenericRepresenter
105
- # include Representable
106
-
107
- # property :title
108
- # property :manager do
109
- # property :title
110
- # end
111
- # end
112
-
113
- # class LabelForm < Reform::Form
114
- # property :location
115
-
116
- # include GenericRepresenter
117
- # validates :title, :presence => true
118
- # property :manager, :inherit => true do
119
- # validates :title, :presence => true
120
- # end
121
- # end
122
- # puts "......"+ LabelForm.representer_class.representable_attrs.get(:title).inspect
123
-
124
-
125
- # it do
126
- # form = LabelForm.new(OpenStruct.new(:manager => OpenStruct.new))
127
- # form.validate({"manager" => {}, "title"=>""}) # it's important to pass both nested and scalar here!
128
- # form.errors.messages.must_equal(:title=>["can't be blank"], :"manager.title"=>["can't be blank"], )
129
- # end
130
102
  end
@@ -0,0 +1,15 @@
1
+ require "test_helper"
2
+
3
+ class ParsePipelineTest < MiniTest::Spec
4
+ Album = Struct.new(:name)
5
+
6
+ class AlbumForm < Reform::Form
7
+ property :name, deserializer: { parse_pipeline: ->(input, options) { Representable::Pipeline[->(input, options) { options[:represented].name = input.inspect }] } }
8
+ end
9
+
10
+ it "allows passing :parse_pipeline directly" do
11
+ form = AlbumForm.new(Album.new)
12
+ form.validate("name" => "Greatest Hits")
13
+ form.name.must_equal "{\"name\"=>\"Greatest Hits\"}"
14
+ end
15
+ end
@@ -6,18 +6,19 @@ class PopulatorTest < MiniTest::Spec
6
6
  Artist = Struct.new(:name)
7
7
 
8
8
  class AlbumForm < Reform::Form
9
- property :name
9
+ property :name, populator: ->(options) { self.name = options[:fragment].reverse }
10
10
  validates :name, presence: true
11
11
 
12
12
  collection :songs,
13
- populator: lambda { |fragment, collection, index, options|
14
- # collection = options.binding.get # we don't need this anymore as this comes in for free!
13
+ populator: ->(options) {
14
+ fragment, collection, index = options[:fragment], options[:model], options[:index]
15
+
15
16
  (item = collection[index]) ? item : collection.insert(index, Song.new) } do
16
17
 
17
18
  property :title
18
19
  validates :title, presence: true
19
20
 
20
- property :composer, populator: lambda { |fragment, model, options| model || self.composer= Artist.new } do
21
+ property :composer, populator: ->(options) { options[:model] || self.composer= Artist.new } do
21
22
  property :name
22
23
  validates :name, presence: true
23
24
  end
@@ -25,7 +26,7 @@ class PopulatorTest < MiniTest::Spec
25
26
 
26
27
  # property :artist, populator: lambda { |fragment, options| (item = options.binding.get) ? item : Artist.new } do
27
28
  # NOTE: we have to document that model here is the twin!
28
- property :artist, populator: lambda { |fragment, twin, *| twin || self.artist = Artist.new } do
29
+ property :artist, populator: ->(options) { options[:model] || self.artist = Artist.new } do
29
30
  property :name
30
31
  end
31
32
  end
@@ -38,6 +39,14 @@ class PopulatorTest < MiniTest::Spec
38
39
 
39
40
  let (:form) { AlbumForm.new(album) }
40
41
 
42
+ it "runs populator on scalar" do
43
+ form.validate(
44
+ "name" => "override me!"
45
+ )
46
+
47
+ form.name.must_equal "!em edirrevo"
48
+ end
49
+
41
50
  # changing existing property :artist.
42
51
  # TODO: check with artist==nil
43
52
  it do
@@ -89,6 +98,26 @@ class PopulatorTest < MiniTest::Spec
89
98
  end
90
99
  end
91
100
 
101
+ class PopulateWithMethodTest < Minitest::Spec
102
+ class AlbumForm < Reform::Form
103
+ property :title, populator: :title!
104
+
105
+ def title!(options)
106
+ self.title = options[:fragment].reverse
107
+ end
108
+ end
109
+
110
+ let (:form) { AlbumForm.new(Album.new) }
111
+
112
+ it "runs populator method" do
113
+ form.validate(
114
+ "title" => "override me!"
115
+ )
116
+
117
+ form.title.must_equal "!em edirrevo"
118
+ end
119
+ end
120
+
92
121
  class PopulateIfEmptyTest < MiniTest::Spec
93
122
  Song = Struct.new(:title, :album, :composer)
94
123
  Album = Struct.new(:name, :songs, :artist)
@@ -122,7 +151,7 @@ class PopulateIfEmptyTest < MiniTest::Spec
122
151
  end
123
152
  end
124
153
 
125
- property :artist, populate_if_empty: lambda { |*args| create_artist(args) } do # methods work, too.
154
+ property :artist, populate_if_empty: lambda { |args| create_artist(args[:fragment], args[:user_options]) } do # methods work, too.
126
155
  property :name
127
156
  end
128
157
 
@@ -130,8 +159,8 @@ class PopulateIfEmptyTest < MiniTest::Spec
130
159
  class Sting < Artist
131
160
  attr_accessor :args
132
161
  end
133
- def create_artist(args)
134
- Sting.new.tap { |artist| artist.args=(args) }
162
+ def create_artist(input, user_options)
163
+ Sting.new.tap { |artist| artist.args=([input, user_options].to_s) }
135
164
  end
136
165
  end
137
166
 
@@ -171,7 +200,7 @@ class PopulateIfEmptyTest < MiniTest::Spec
171
200
  end
172
201
 
173
202
  # trigger artist populator. lambda calling form instance method.
174
- it do
203
+ it "xxxx" do
175
204
  form = AlbumForm.new(album = Album.new)
176
205
  form.validate("artist" => {"name" => "From Autumn To Ashes"})
177
206
 
@@ -179,7 +208,7 @@ class PopulateIfEmptyTest < MiniTest::Spec
179
208
  # test lambda was executed in form context.
180
209
  form.artist.model.must_be_instance_of AlbumForm::Sting
181
210
  # test lambda block arguments.
182
- form.artist.model.args.to_s.must_equal "[{\"name\"=>\"From Autumn To Ashes\"}, {}]"
211
+ form.artist.model.args.to_s.must_equal "[{\"name\"=>\"From Autumn To Ashes\"}, nil]"
183
212
 
184
213
  album.artist.must_equal nil
185
214
  end
@@ -206,8 +235,8 @@ class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
206
235
  validates :title, presence: true
207
236
  end
208
237
 
209
- def delete_song!(fragment, *)
210
- songs.delete(songs[0]) and return true if fragment["title"] == "Broken, delete me!"
238
+ def delete_song!(options)
239
+ songs.delete(songs[0]) and return true if options[:fragment]["title"] == "Broken, delete me!"
211
240
  false
212
241
  end
213
242
  end
@@ -0,0 +1,28 @@
1
+ require "test_helper"
2
+
3
+ class PopulatorSkipTest < MiniTest::Spec
4
+ Album = Struct.new(:songs)
5
+ Song = Struct.new(:title)
6
+
7
+
8
+ class AlbumForm < Reform::Form
9
+ collection :songs,
10
+ populator: ->(options) {
11
+ return skip! if options[:fragment][:title] == "Good"
12
+ songs[options[:index]]
13
+ } do
14
+ property :title
15
+ end
16
+ end
17
+
18
+ it do
19
+ form = AlbumForm.new(Album.new([Song.new, Song.new]))
20
+ hash = {songs: [{title: "Good"}, {title: "Bad"}]}
21
+
22
+ form.validate(hash)
23
+
24
+ form.songs.size.must_equal 2
25
+ form.songs[0].title.must_equal nil
26
+ form.songs[1].title.must_equal "Bad"
27
+ end
28
+ end
data/test/reform_test.rb CHANGED
@@ -106,7 +106,7 @@ class ReformTest < ReformSpec
106
106
 
107
107
  before { form.validate("name" => "Diesel Boy") }
108
108
 
109
- it "pushes data to models" do
109
+ it "xxpushes data to models" do
110
110
  form.save
111
111
 
112
112
  comp.name.must_equal "Diesel Boy"
data/test/skip_if_test.rb CHANGED
@@ -5,7 +5,7 @@ class SkipIfTest < BaseTest
5
5
  class AlbumForm < Reform::Form
6
6
  property :title
7
7
 
8
- property :hit, skip_if: lambda { |fragment, *| fragment["title"].blank? } do
8
+ property :hit, skip_if: lambda { |options| options[:fragment]["title"].blank? } do
9
9
  property :title
10
10
  validates :title, presence: true
11
11
  end
@@ -14,8 +14,8 @@ class SkipIfTest < BaseTest
14
14
  property :title
15
15
  end
16
16
 
17
- def skip_song?(fragment, options)
18
- fragment["title"].nil?
17
+ def skip_song?(options)
18
+ options[:fragment]["title"].nil?
19
19
  end
20
20
  end
21
21
 
@@ -62,4 +62,11 @@ class SkipIfAllBlankTest < BaseTest
62
62
  form.songs.size.must_equal 1
63
63
  form.songs[0].title.must_equal "Apathy"
64
64
  end
65
+
66
+ it do
67
+ form = AlbumForm.new(OpenStruct.new(songs: []))
68
+ form.validate("songs" => [{"title"=>"", "length" => ""}, {"title"=>"Apathy"}]).must_equal true
69
+ form.songs.size.must_equal 1
70
+ form.songs[0].title.must_equal "Apathy"
71
+ end
65
72
  end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,7 @@
1
- require 'reform'
1
+ require "reform"
2
2
  require 'minitest/autorun'
3
3
  require "representable/debug"
4
+ require "declarative/testing"
4
5
  require "pp"
5
6
 
6
7
  class ReformSpec < MiniTest::Spec
@@ -62,6 +63,10 @@ MiniTest::Spec.class_eval do
62
63
  end
63
64
  end
64
65
 
66
+ def self.rails4_2?
67
+ ::ActiveModel::VERSION::MAJOR == 4 and ::ActiveModel::VERSION::MINOR == 2
68
+ end
69
+
65
70
  def self.rails4_0?
66
71
  ::ActiveModel::VERSION::MAJOR == 4 and ::ActiveModel::VERSION::MINOR == 0
67
72
  end
@@ -73,7 +78,11 @@ end
73
78
 
74
79
  require "reform/form/active_model/validations"
75
80
  Reform::Contract.class_eval do
76
- include Reform::Form::ActiveModel::Validations
81
+ feature Reform::Form::ActiveModel::Validations
82
+ end
83
+ # FIXME!
84
+ Reform::Form.class_eval do
85
+ feature Reform::Form::ActiveModel::Validations
77
86
  end
78
87
 
79
88
  I18n.load_path << Dir['test/dummy/config/locales/*.yml']
data/test/unique_test.rb CHANGED
@@ -19,7 +19,7 @@ class UniquenessValidatorOnCreateTest < MiniTest::Spec
19
19
 
20
20
  form = SongForm.new(Song.new)
21
21
  form.validate("title" => "How Many Tears").must_equal false
22
- form.errors.to_s.must_equal "{:title=>[\"title must be unique.\"]}"
22
+ form.errors.to_s.must_equal "{:title=>[\"has already been taken\"]}"
23
23
  end
24
24
  end
25
25
 
@@ -61,4 +61,75 @@ class UniqueWithCompositionTest < MiniTest::Spec
61
61
  form.validate("title" => "How Many Tears").must_equal true
62
62
  form.save
63
63
  end
64
+ end
65
+
66
+
67
+ class UniqueValidatorWithScopeTest < MiniTest::Spec
68
+ class SongForm < Reform::Form
69
+ include ActiveRecord
70
+ property :album_id
71
+ property :title
72
+ validates :title, unique: { scope: :album_id }
73
+ end
74
+
75
+ it do
76
+ Song.delete_all
77
+
78
+ album = Album.new
79
+ album.save
80
+
81
+ form = SongForm.new(Song.new)
82
+ form.validate(album_id: album.id, title: 'How Many Tears').must_equal true
83
+ form.save
84
+
85
+ form = SongForm.new(Song.new)
86
+ form.validate(album_id: album.id, title: 'How Many Tears').must_equal false
87
+ form.errors.to_s.must_equal "{:title=>[\"has already been taken\"]}"
88
+
89
+ album = Album.new
90
+ album.save
91
+
92
+ form = SongForm.new(Song.new)
93
+ form.validate(album_id: album.id, title: 'How Many Tears').must_equal true
94
+ end
95
+ end
96
+
97
+ class UniqueValidatorWithScopeArrayTest < MiniTest::Spec
98
+ class SongForm < Reform::Form
99
+ include ActiveRecord
100
+ property :album_id
101
+ property :artist_id
102
+ property :title
103
+ validates :title, unique: { scope: [:album_id, :artist_id] }
104
+ end
105
+
106
+ it do
107
+ Song.delete_all
108
+
109
+ album1 = Album.new
110
+ album1.save
111
+
112
+ artist1 = Artist.new
113
+ artist1.save
114
+
115
+ form = SongForm.new(Song.new)
116
+ form.validate(album_id: album1.id, artist_id: artist1.id, title: 'How Many Tears').must_equal true
117
+ form.save
118
+
119
+ form = SongForm.new(Song.new)
120
+ form.validate(album_id: album1.id, artist_id: artist1.id, title: 'How Many Tears').must_equal false
121
+ form.errors.to_s.must_equal "{:title=>[\"has already been taken\"]}"
122
+
123
+ album2 = Album.new
124
+ album2.save
125
+
126
+ form = SongForm.new(Song.new)
127
+ form.validate(album_id: album2.id, artist_id: artist1.id, title: 'How Many Tears').must_equal true
128
+
129
+ artist2 = Artist.new
130
+ artist2.save
131
+
132
+ form = SongForm.new(Song.new)
133
+ form.validate(album_id: album1.id, artist_id: artist2.id, title: 'How Many Tears').must_equal true
134
+ end
64
135
  end