cooklang 1.0.0 → 1.0.1
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 +4 -4
- data/.github/workflows/test.yml +35 -0
- data/.gitignore +12 -0
- data/.qlty/.gitignore +7 -0
- data/.qlty/configs/.yamllint.yaml +21 -0
- data/.qlty/qlty.toml +101 -0
- data/.rspec +3 -0
- data/.rubocop.yml +340 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +84 -0
- data/README.md +10 -5
- data/Rakefile +12 -0
- data/cooklang.gemspec +35 -0
- data/lib/cooklang/builders/recipe_builder.rb +64 -0
- data/lib/cooklang/builders/step_builder.rb +76 -0
- data/lib/cooklang/lexer.rb +5 -14
- data/lib/cooklang/parser.rb +24 -653
- data/lib/cooklang/parsers/cookware_parser.rb +133 -0
- data/lib/cooklang/parsers/ingredient_parser.rb +179 -0
- data/lib/cooklang/parsers/timer_parser.rb +135 -0
- data/lib/cooklang/processors/element_parser.rb +45 -0
- data/lib/cooklang/processors/metadata_processor.rb +129 -0
- data/lib/cooklang/processors/step_processor.rb +208 -0
- data/lib/cooklang/processors/token_processor.rb +104 -0
- data/lib/cooklang/recipe.rb +25 -15
- data/lib/cooklang/step.rb +12 -2
- data/lib/cooklang/timer.rb +3 -1
- data/lib/cooklang/token_stream.rb +130 -0
- data/lib/cooklang/version.rb +1 -1
- data/spec/comprehensive_spec.rb +179 -0
- data/spec/cooklang_spec.rb +38 -0
- data/spec/fixtures/canonical.yaml +837 -0
- data/spec/formatters/text_spec.rb +189 -0
- data/spec/integration/canonical_spec.rb +211 -0
- data/spec/lexer_spec.rb +357 -0
- data/spec/models/cookware_spec.rb +116 -0
- data/spec/models/ingredient_spec.rb +192 -0
- data/spec/models/metadata_spec.rb +241 -0
- data/spec/models/note_spec.rb +65 -0
- data/spec/models/recipe_spec.rb +171 -0
- data/spec/models/section_spec.rb +65 -0
- data/spec/models/step_spec.rb +236 -0
- data/spec/models/timer_spec.rb +173 -0
- data/spec/parser_spec.rb +398 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/token_stream_spec.rb +278 -0
- metadata +162 -6
@@ -0,0 +1,241 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Cooklang::Metadata do
|
6
|
+
describe "#initialize" do
|
7
|
+
it "creates empty metadata" do
|
8
|
+
metadata = described_class.new
|
9
|
+
|
10
|
+
expect(metadata).to be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it "creates metadata from hash" do
|
14
|
+
data = { "title" => "Test Recipe", "servings" => 4 }
|
15
|
+
metadata = described_class.new(data)
|
16
|
+
|
17
|
+
expect(metadata["title"]).to eq("Test Recipe")
|
18
|
+
expect(metadata["servings"]).to eq(4)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "converts symbol keys to strings" do
|
22
|
+
data = { title: "Test Recipe", servings: 4 }
|
23
|
+
metadata = described_class.new(data)
|
24
|
+
|
25
|
+
expect(metadata["title"]).to eq("Test Recipe")
|
26
|
+
expect(metadata["servings"]).to eq(4)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "hash access methods" do
|
31
|
+
let(:metadata) { described_class.new(title: "Test Recipe", servings: 4) }
|
32
|
+
|
33
|
+
describe "#[]=" do
|
34
|
+
it "converts keys to strings" do
|
35
|
+
metadata[:prep_time] = "10 minutes"
|
36
|
+
|
37
|
+
expect(metadata["prep_time"]).to eq("10 minutes")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#[]" do
|
42
|
+
it "converts keys to strings" do
|
43
|
+
expect(metadata[:title]).to eq("Test Recipe")
|
44
|
+
expect(metadata["title"]).to eq("Test Recipe")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#key?" do
|
49
|
+
it "converts keys to strings" do
|
50
|
+
expect(metadata.key?(:title)).to be true
|
51
|
+
expect(metadata.key?("title")).to be true
|
52
|
+
expect(metadata.key?(:nonexistent)).to be false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#delete" do
|
57
|
+
it "converts keys to strings" do
|
58
|
+
metadata.delete(:title)
|
59
|
+
|
60
|
+
expect(metadata).not_to have_key("title")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#fetch" do
|
65
|
+
it "converts keys to strings" do
|
66
|
+
expect(metadata.fetch(:title)).to eq("Test Recipe")
|
67
|
+
expect(metadata.fetch(:nonexistent, "default")).to eq("default")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#to_h" do
|
73
|
+
it "returns plain hash" do
|
74
|
+
metadata = described_class.new(title: "Test Recipe", servings: 4)
|
75
|
+
|
76
|
+
hash = metadata.to_h
|
77
|
+
|
78
|
+
expect(hash).to be_a(Hash)
|
79
|
+
expect(hash).not_to be_a(described_class)
|
80
|
+
expect(hash).to eq({ "title" => "Test Recipe", "servings" => 4 })
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "recipe-specific accessors" do
|
85
|
+
let(:metadata) { described_class.new }
|
86
|
+
|
87
|
+
describe "#servings" do
|
88
|
+
it "returns integer servings" do
|
89
|
+
metadata["servings"] = "4"
|
90
|
+
|
91
|
+
expect(metadata.servings).to eq(4)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns nil when not set" do
|
95
|
+
expect(metadata.servings).to be_nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#servings=" do
|
100
|
+
it "sets servings" do
|
101
|
+
metadata.servings = 6
|
102
|
+
|
103
|
+
expect(metadata["servings"]).to eq(6)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#prep_time" do
|
108
|
+
it "returns prep_time" do
|
109
|
+
metadata["prep_time"] = "15 minutes"
|
110
|
+
|
111
|
+
expect(metadata.prep_time).to eq("15 minutes")
|
112
|
+
end
|
113
|
+
|
114
|
+
it "returns prep-time as fallback" do
|
115
|
+
metadata["prep-time"] = "15 minutes"
|
116
|
+
|
117
|
+
expect(metadata.prep_time).to eq("15 minutes")
|
118
|
+
end
|
119
|
+
|
120
|
+
it "returns nil when not set" do
|
121
|
+
expect(metadata.prep_time).to be_nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#prep_time=" do
|
126
|
+
it "sets prep_time" do
|
127
|
+
metadata.prep_time = "20 minutes"
|
128
|
+
|
129
|
+
expect(metadata["prep_time"]).to eq("20 minutes")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "#cook_time" do
|
134
|
+
it "returns cook_time" do
|
135
|
+
metadata["cook_time"] = "30 minutes"
|
136
|
+
|
137
|
+
expect(metadata.cook_time).to eq("30 minutes")
|
138
|
+
end
|
139
|
+
|
140
|
+
it "returns cook-time as fallback" do
|
141
|
+
metadata["cook-time"] = "30 minutes"
|
142
|
+
|
143
|
+
expect(metadata.cook_time).to eq("30 minutes")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "#cook_time=" do
|
148
|
+
it "sets cook_time" do
|
149
|
+
metadata.cook_time = "25 minutes"
|
150
|
+
|
151
|
+
expect(metadata["cook_time"]).to eq("25 minutes")
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#total_time" do
|
156
|
+
it "returns total_time" do
|
157
|
+
metadata["total_time"] = "45 minutes"
|
158
|
+
|
159
|
+
expect(metadata.total_time).to eq("45 minutes")
|
160
|
+
end
|
161
|
+
|
162
|
+
it "returns total-time as fallback" do
|
163
|
+
metadata["total-time"] = "45 minutes"
|
164
|
+
|
165
|
+
expect(metadata.total_time).to eq("45 minutes")
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "#total_time=" do
|
170
|
+
it "sets total_time" do
|
171
|
+
metadata.total_time = "50 minutes"
|
172
|
+
|
173
|
+
expect(metadata["total_time"]).to eq("50 minutes")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "#title" do
|
178
|
+
it "returns title" do
|
179
|
+
metadata["title"] = "Chocolate Cake"
|
180
|
+
|
181
|
+
expect(metadata.title).to eq("Chocolate Cake")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "#title=" do
|
186
|
+
it "sets title" do
|
187
|
+
metadata.title = "Vanilla Cake"
|
188
|
+
|
189
|
+
expect(metadata["title"]).to eq("Vanilla Cake")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "#source" do
|
194
|
+
it "returns source" do
|
195
|
+
metadata["source"] = "cookbook.com"
|
196
|
+
|
197
|
+
expect(metadata.source).to eq("cookbook.com")
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "#source=" do
|
202
|
+
it "sets source" do
|
203
|
+
metadata.source = "my-blog.com"
|
204
|
+
|
205
|
+
expect(metadata["source"]).to eq("my-blog.com")
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "#tags" do
|
210
|
+
it "returns array when tags is array" do
|
211
|
+
metadata["tags"] = ["dessert", "chocolate"]
|
212
|
+
|
213
|
+
expect(metadata.tags).to eq(["dessert", "chocolate"])
|
214
|
+
end
|
215
|
+
|
216
|
+
it "splits string tags on comma" do
|
217
|
+
metadata["tags"] = "dessert, chocolate, sweet"
|
218
|
+
|
219
|
+
expect(metadata.tags).to eq(["dessert", "chocolate", "sweet"])
|
220
|
+
end
|
221
|
+
|
222
|
+
it "returns empty array when not set" do
|
223
|
+
expect(metadata.tags).to eq([])
|
224
|
+
end
|
225
|
+
|
226
|
+
it "returns empty array for non-string, non-array values" do
|
227
|
+
metadata["tags"] = 123
|
228
|
+
|
229
|
+
expect(metadata.tags).to eq([])
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "#tags=" do
|
234
|
+
it "sets tags" do
|
235
|
+
metadata.tags = ["breakfast", "quick"]
|
236
|
+
|
237
|
+
expect(metadata["tags"]).to eq(["breakfast", "quick"])
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Cooklang::Note do
|
6
|
+
describe "#initialize" do
|
7
|
+
it "creates note with content" do
|
8
|
+
note = described_class.new(content: "This is a note")
|
9
|
+
expect(note.content).to eq("This is a note")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "converts content to string and freezes it" do
|
13
|
+
note = described_class.new(content: 123)
|
14
|
+
expect(note.content).to eq("123")
|
15
|
+
expect(note.content).to be_frozen
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#to_s" do
|
20
|
+
it "returns content" do
|
21
|
+
note = described_class.new(content: "Test note")
|
22
|
+
expect(note.to_s).to eq("Test note")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#to_h" do
|
27
|
+
it "returns hash representation" do
|
28
|
+
note = described_class.new(content: "Test note")
|
29
|
+
expect(note.to_h).to eq({ content: "Test note" })
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#==" do
|
34
|
+
it "returns true for notes with same content" do
|
35
|
+
note1 = described_class.new(content: "Same content")
|
36
|
+
note2 = described_class.new(content: "Same content")
|
37
|
+
expect(note1 == note2).to be_truthy
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns false for notes with different content" do
|
41
|
+
note1 = described_class.new(content: "Content 1")
|
42
|
+
note2 = described_class.new(content: "Content 2")
|
43
|
+
expect(note1 == note2).to be_falsey
|
44
|
+
end
|
45
|
+
|
46
|
+
it "returns false for non-Note objects" do
|
47
|
+
note = described_class.new(content: "Test")
|
48
|
+
expect(note == "Test").to be_falsey
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#hash" do
|
53
|
+
it "generates same hash for equal notes" do
|
54
|
+
note1 = described_class.new(content: "Test")
|
55
|
+
note2 = described_class.new(content: "Test")
|
56
|
+
expect(note1.hash).to eq(note2.hash)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "generates different hash for different notes" do
|
60
|
+
note1 = described_class.new(content: "Test 1")
|
61
|
+
note2 = described_class.new(content: "Test 2")
|
62
|
+
expect(note1.hash).not_to eq(note2.hash)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Cooklang::Recipe do
|
6
|
+
let(:ingredient) { Cooklang::Ingredient.new(name: "flour", quantity: 125, unit: "g") }
|
7
|
+
let(:cookware) { Cooklang::Cookware.new(name: "pan") }
|
8
|
+
let(:timer) { Cooklang::Timer.new(duration: 5, unit: "minutes") }
|
9
|
+
let(:step) { Cooklang::Step.new(segments: ["Mix the ", { type: :ingredient, name: "flour" }]) }
|
10
|
+
let(:metadata) { Cooklang::Metadata.new(title: "Test Recipe") }
|
11
|
+
|
12
|
+
describe "#initialize" do
|
13
|
+
it "creates a recipe with all components" do
|
14
|
+
recipe = described_class.new(
|
15
|
+
ingredients: [ingredient],
|
16
|
+
cookware: [cookware],
|
17
|
+
timers: [timer],
|
18
|
+
steps: [step],
|
19
|
+
metadata: metadata
|
20
|
+
)
|
21
|
+
|
22
|
+
expect(recipe.ingredients).to eq([ingredient])
|
23
|
+
expect(recipe.cookware).to eq([cookware])
|
24
|
+
expect(recipe.timers).to eq([timer])
|
25
|
+
expect(recipe.steps).to eq([step])
|
26
|
+
expect(recipe.metadata).to eq(metadata)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "freezes arrays to prevent modification" do
|
30
|
+
recipe = described_class.new(
|
31
|
+
ingredients: [ingredient],
|
32
|
+
cookware: [cookware],
|
33
|
+
timers: [timer],
|
34
|
+
steps: [step],
|
35
|
+
metadata: metadata
|
36
|
+
)
|
37
|
+
|
38
|
+
expect(recipe.ingredients).to be_frozen
|
39
|
+
expect(recipe.cookware).to be_frozen
|
40
|
+
expect(recipe.timers).to be_frozen
|
41
|
+
expect(recipe.steps).to be_frozen
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#ingredients_hash" do
|
46
|
+
it "returns ingredients as a hash with quantity and unit" do
|
47
|
+
ingredient1 = Cooklang::Ingredient.new(name: "flour", quantity: 125, unit: "g")
|
48
|
+
ingredient2 = Cooklang::Ingredient.new(name: "salt", quantity: 1, unit: "pinch")
|
49
|
+
|
50
|
+
recipe = described_class.new(
|
51
|
+
ingredients: [ingredient1, ingredient2],
|
52
|
+
cookware: [],
|
53
|
+
timers: [],
|
54
|
+
steps: [],
|
55
|
+
metadata: Cooklang::Metadata.new
|
56
|
+
)
|
57
|
+
|
58
|
+
expected = {
|
59
|
+
"flour" => { quantity: 125, unit: "g" },
|
60
|
+
"salt" => { quantity: 1, unit: "pinch" }
|
61
|
+
}
|
62
|
+
|
63
|
+
expect(recipe.ingredients_hash).to eq(expected)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "omits nil values" do
|
67
|
+
ingredient = Cooklang::Ingredient.new(name: "salt")
|
68
|
+
|
69
|
+
recipe = described_class.new(
|
70
|
+
ingredients: [ingredient],
|
71
|
+
cookware: [],
|
72
|
+
timers: [],
|
73
|
+
steps: [],
|
74
|
+
metadata: Cooklang::Metadata.new
|
75
|
+
)
|
76
|
+
|
77
|
+
expect(recipe.ingredients_hash).to eq({ "salt" => {} })
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#steps_text" do
|
82
|
+
it "returns text representation of steps" do
|
83
|
+
step1 = Cooklang::Step.new(segments: ["Mix the ingredients"])
|
84
|
+
step2 = Cooklang::Step.new(segments: ["Cook for ", { type: :timer, name: "timer" }])
|
85
|
+
|
86
|
+
recipe = described_class.new(
|
87
|
+
ingredients: [],
|
88
|
+
cookware: [],
|
89
|
+
timers: [],
|
90
|
+
steps: [step1, step2],
|
91
|
+
metadata: Cooklang::Metadata.new
|
92
|
+
)
|
93
|
+
|
94
|
+
expect(recipe.steps_text).to eq(["Mix the ingredients", "Cook for timer"])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#to_h" do
|
99
|
+
it "returns complete hash representation" do
|
100
|
+
recipe = described_class.new(
|
101
|
+
ingredients: [ingredient],
|
102
|
+
cookware: [cookware],
|
103
|
+
timers: [timer],
|
104
|
+
steps: [step],
|
105
|
+
metadata: metadata
|
106
|
+
)
|
107
|
+
|
108
|
+
hash = recipe.to_h
|
109
|
+
|
110
|
+
expect(hash[:ingredients]).to eq([ingredient.to_h])
|
111
|
+
expect(hash[:cookware]).to eq([cookware.to_h])
|
112
|
+
expect(hash[:timers]).to eq([timer.to_h])
|
113
|
+
expect(hash[:steps]).to eq([step.to_h])
|
114
|
+
expect(hash[:metadata]).to eq(metadata.to_h)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#==" do
|
119
|
+
it "returns true for recipes with same content" do
|
120
|
+
recipe1 = described_class.new(
|
121
|
+
ingredients: [ingredient],
|
122
|
+
cookware: [cookware],
|
123
|
+
timers: [timer],
|
124
|
+
steps: [step],
|
125
|
+
metadata: metadata
|
126
|
+
)
|
127
|
+
|
128
|
+
recipe2 = described_class.new(
|
129
|
+
ingredients: [ingredient],
|
130
|
+
cookware: [cookware],
|
131
|
+
timers: [timer],
|
132
|
+
steps: [step],
|
133
|
+
metadata: metadata
|
134
|
+
)
|
135
|
+
|
136
|
+
expect(recipe1).to eq(recipe2)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "returns false for recipes with different content" do
|
140
|
+
recipe1 = described_class.new(
|
141
|
+
ingredients: [ingredient],
|
142
|
+
cookware: [],
|
143
|
+
timers: [],
|
144
|
+
steps: [],
|
145
|
+
metadata: Cooklang::Metadata.new
|
146
|
+
)
|
147
|
+
|
148
|
+
recipe2 = described_class.new(
|
149
|
+
ingredients: [],
|
150
|
+
cookware: [cookware],
|
151
|
+
timers: [],
|
152
|
+
steps: [],
|
153
|
+
metadata: Cooklang::Metadata.new
|
154
|
+
)
|
155
|
+
|
156
|
+
expect(recipe1).not_to eq(recipe2)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "returns false for non-Recipe objects" do
|
160
|
+
recipe = described_class.new(
|
161
|
+
ingredients: [],
|
162
|
+
cookware: [],
|
163
|
+
timers: [],
|
164
|
+
steps: [],
|
165
|
+
metadata: Cooklang::Metadata.new
|
166
|
+
)
|
167
|
+
|
168
|
+
expect(recipe).not_to eq("not a recipe")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Cooklang::Section do
|
6
|
+
describe "#initialize" do
|
7
|
+
it "creates section with name" do
|
8
|
+
section = described_class.new(name: "Preparation")
|
9
|
+
expect(section.name).to eq("Preparation")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "converts name to string and freezes it" do
|
13
|
+
section = described_class.new(name: 123)
|
14
|
+
expect(section.name).to eq("123")
|
15
|
+
expect(section.name).to be_frozen
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#to_s" do
|
20
|
+
it "returns name" do
|
21
|
+
section = described_class.new(name: "Cooking")
|
22
|
+
expect(section.to_s).to eq("Cooking")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#to_h" do
|
27
|
+
it "returns hash representation" do
|
28
|
+
section = described_class.new(name: "Preparation")
|
29
|
+
expect(section.to_h).to eq({ name: "Preparation", steps: [] })
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#==" do
|
34
|
+
it "returns true for sections with same name" do
|
35
|
+
section1 = described_class.new(name: "Prep")
|
36
|
+
section2 = described_class.new(name: "Prep")
|
37
|
+
expect(section1 == section2).to be_truthy
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns false for sections with different names" do
|
41
|
+
section1 = described_class.new(name: "Prep")
|
42
|
+
section2 = described_class.new(name: "Cook")
|
43
|
+
expect(section1 == section2).to be_falsey
|
44
|
+
end
|
45
|
+
|
46
|
+
it "returns false for non-Section objects" do
|
47
|
+
section = described_class.new(name: "Prep")
|
48
|
+
expect(section == "Prep").to be_falsey
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#hash" do
|
53
|
+
it "generates same hash for equal sections" do
|
54
|
+
section1 = described_class.new(name: "Test")
|
55
|
+
section2 = described_class.new(name: "Test")
|
56
|
+
expect(section1.hash).to eq(section2.hash)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "generates different hash for different sections" do
|
60
|
+
section1 = described_class.new(name: "Test 1")
|
61
|
+
section2 = described_class.new(name: "Test 2")
|
62
|
+
expect(section1.hash).not_to eq(section2.hash)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|