Skip to content

Commit 810d8c9

Browse files
committed
Fix frozen string literal issue
1 parent 292cb22 commit 810d8c9

File tree

5 files changed

+160
-10
lines changed

5 files changed

+160
-10
lines changed

.github/workflows/ci.yml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,21 @@ permissions:
1212
contents: read
1313

1414
jobs:
15-
Shared:
16-
uses: fog/.github/.github/workflows/ci.yml@v1.4.0
15+
test:
16+
17+
runs-on: ubuntu-latest
18+
19+
strategy:
20+
matrix:
21+
ruby-version: ['3.0', '3.1', '3.2', '3.3', 'head']
22+
continue-on-error: ${{ matrix.ruby-version == 'head' }}
23+
24+
steps:
25+
- uses: actions/checkout@v4
26+
- name: Set up Ruby
27+
uses: ruby/setup-ruby@v1
28+
with:
29+
ruby-version: ${{ matrix.ruby-version }}
30+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31+
- name: Run tests
32+
run: bundle exec rake RUBYOPT="--enable-frozen-string-literal"

lib/fog/parsers/base.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def reset
1818
end
1919

2020
def characters(string)
21-
@value ||= ''
21+
@value ||= +''
2222
@value << string
2323
end
2424

lib/fog/to_hash_document.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,22 @@ def initialize
55
end
66

77
def characters(string)
8-
@value ||= ""
8+
@value ||= +''
99
@value << string.strip
1010
end
1111

1212
def end_element(name)
1313
last = @stack.pop
14-
if last.empty? && @value.empty?
15-
@stack.last[name.to_sym] = ""
14+
@stack.push({}) if @stack.empty?
15+
16+
if last&.empty? && @value.empty?
17+
@stack.last[name.to_sym] = +''
1618
elsif last == { :i_nil => "true" }
1719
@stack.last[name.to_sym] = nil
1820
elsif !@value.empty?
1921
@stack.last[name.to_sym] = @value
2022
end
21-
@value = ""
23+
@value = +''
2224
end
2325

2426
def body
@@ -30,7 +32,7 @@ def response
3032
end
3133

3234
def start_element(name, attributes = [])
33-
@value = ""
35+
@value = +''
3436
parsed_attributes = {}
3537
until attributes.empty?
3638
if attributes.first.is_a?(Array)

lib/fog/xml/response.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class Response
44
def initialize(parser)
55
@parser = parser
66
@data_stream = Nokogiri::XML::SAX::PushParser.new(parser)
7-
@response_string = ""
7+
@response_string = +''
88
end
99

1010
def call(chunk, _remaining, _total)
@@ -14,7 +14,7 @@ def call(chunk, _remaining, _total)
1414

1515
def rewind
1616
@parser.reset
17-
@response_string = ""
17+
@response_string = +''
1818
end
1919

2020
def finish

spec/fog/to_hash_document_spec.rb

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
require 'minitest_helper'
2+
require 'fog/xml'
3+
4+
# We expose accessors just for testing purposes
5+
Fog::ToHashDocument.attr_accessor(:value, :stack)
6+
7+
describe Fog::ToHashDocument do
8+
before do
9+
@document = Fog::ToHashDocument.new
10+
end
11+
12+
describe '#characters' do
13+
it 'appends characters to @value' do
14+
@document.characters("some text")
15+
_(@document.value).must_equal "some text"
16+
end
17+
18+
it 'strips whitespace from characters' do
19+
@document.characters(" some text ")
20+
_(@document.value).must_equal "some text"
21+
end
22+
end
23+
24+
describe '#end_element' do
25+
before do
26+
@document.stack << {}
27+
@document.characters("some text")
28+
end
29+
30+
it 'adds element with text content to the stack' do
31+
@document.end_element('element')
32+
33+
_(@document.stack.last).must_equal({ element: "some text" })
34+
end
35+
36+
it 'can mutate the new empty value' do
37+
@document.end_element('element')
38+
39+
_(@document.value).must_equal("")
40+
41+
# Mutate the new empty value even when frozen string literals are enabled
42+
_(@document.characters('one'))
43+
end
44+
45+
it 'adds empty string if element is empty and value is empty' do
46+
@document.value = ""
47+
@document.end_element('element')
48+
_(@document.stack.last).must_equal({ element: "" })
49+
end
50+
51+
it 'adds nil if element has :i_nil attribute' do
52+
@document.stack.last[:i_nil] = "true"
53+
@document.value = ""
54+
55+
@document.end_element('element')
56+
57+
_(@document.stack.last).must_equal({ element: nil })
58+
end
59+
end
60+
61+
describe '#body' do
62+
it 'returns the first element of the stack' do
63+
@document.stack << { key: "value" }
64+
65+
_(@document.body).must_equal({ key: "value" })
66+
end
67+
end
68+
69+
describe '#response' do
70+
it 'returns the body' do
71+
@document.stack << { key: "value" }
72+
73+
_(@document.response).must_equal({ key: "value" })
74+
end
75+
end
76+
77+
describe '#start_element' do
78+
it 'parses attributes correctly' do
79+
@document.start_element('element', [%w[key value]])
80+
81+
_(@document.stack.last).must_equal({ key: 'value' })
82+
end
83+
84+
it 'handles elements without attributes' do
85+
@document.start_element('element')
86+
87+
_(@document.stack.last).must_equal({})
88+
end
89+
90+
it 'adds nested elements to the stack' do
91+
@document.start_element('parent')
92+
@document.start_element('child')
93+
94+
_(@document.stack).must_equal([ {child: {} }, { child: {} }, {}])
95+
end
96+
97+
it 'adds nested elements with attributes to the stack' do
98+
@document.start_element('parent')
99+
@document.start_element('child', [%w[key value]])
100+
expected = [
101+
{ :child=>{:key=>"value"} },
102+
{ :child=>{:key=>"value"} },
103+
{ :key=>"value"}
104+
]
105+
106+
_(@document.stack).must_equal(expected)
107+
end
108+
109+
it 'handles multiple children elements correctly' do
110+
@document.start_element('parent')
111+
@document.start_element('child1')
112+
@document.end_element('child1')
113+
@document.start_element('child2', [%w[key value]])
114+
@document.end_element('child2')
115+
expected = {
116+
child1: "",
117+
child2: { key: 'value' }
118+
}
119+
120+
_(@document.stack.first).must_equal(expected)
121+
end
122+
123+
it 'handles text content within elements' do
124+
@document.start_element('parent')
125+
@document.characters('some text')
126+
@document.end_element('parent')
127+
128+
expected = { parent: 'some text' }
129+
_(@document.stack.first).must_equal(expected)
130+
end
131+
end
132+
end

0 commit comments

Comments
 (0)