diff options
-rw-r--r-- | lib/chef/util/editor.rb | 92 | ||||
-rw-r--r-- | spec/unit/util/editor_spec.rb | 152 |
2 files changed, 244 insertions, 0 deletions
diff --git a/lib/chef/util/editor.rb b/lib/chef/util/editor.rb new file mode 100644 index 0000000000..973cf48e30 --- /dev/null +++ b/lib/chef/util/editor.rb @@ -0,0 +1,92 @@ +# +# Author:: Chris Bandy (<bandy.chris@gmail.com>) +# Copyright:: Copyright (c) 2014 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + class Util + class Editor + attr_reader :lines + + def initialize(lines) + @lines = lines.to_a.clone + end + + def append_line_after(search, line_to_append) + lines = [] + + @lines.each do |line| + lines << line + lines << line_to_append if line.match(search) + end + + (lines.length - @lines.length).tap { @lines = lines } + end + + def append_line_if_missing(search, line_to_append) + count = 0 + + unless @lines.find { |line| line.match(search) } + count = 1 + @lines << line_to_append + end + + count + end + + def remove_lines(search) + count = 0 + + @lines.delete_if do |line| + count += 1 if line.match(search) + end + + count + end + + def replace(search, replace) + count = 0 + + @lines.map! do |line| + if line.match(search) + count += 1 + line.gsub!(search, replace) + else + line + end + end + + count + end + + def replace_lines(search, replace) + count = 0 + + @lines.map! do |line| + if line.match(search) + count += 1 + replace + else + line + end + end + + count + end + end + end +end + diff --git a/spec/unit/util/editor_spec.rb b/spec/unit/util/editor_spec.rb new file mode 100644 index 0000000000..06370f7de0 --- /dev/null +++ b/spec/unit/util/editor_spec.rb @@ -0,0 +1,152 @@ +require 'spec_helper' +require 'chef/util/editor' + +describe Chef::Util::Editor do + describe '#initialize' do + it 'takes an Enumerable of lines' do + editor = described_class.new(File.open(__FILE__)) + expect(editor.lines).to be == IO.readlines(__FILE__) + end + + it 'makes a copy of an Array' do + array = Array.new + editor = described_class.new(array) + expect(editor.lines).to_not be(array) + end + end + + subject(:editor) { described_class.new(input_lines) } + let(:input_lines) { ['one', 'two', 'two', 'three'] } + + describe '#append_line_after' do + context 'when there is no match' do + subject(:execute) { editor.append_line_after('missing', 'new') } + + it('returns the number of added lines') { should be == 0 } + it 'does not add any lines' do + expect { execute }.to_not change { editor.lines } + end + end + + context 'when there is a match' do + subject(:execute) { editor.append_line_after('two', 'new') } + + it('returns the number of added lines') { should be == 2 } + it 'adds a line after each match' do + execute + expect(editor.lines).to be == ['one', 'two', 'new', 'two', 'new', 'three'] + end + end + + it 'matches a Regexp' do + expect(editor.append_line_after(/^ee/, 'new')).to be == 0 + expect(editor.append_line_after(/ee$/, 'new')).to be == 1 + end + end + + describe '#append_line_if_missing' do + context 'when there is no match' do + subject(:execute) { editor.append_line_if_missing('missing', 'new') } + + it('returns the number of added lines') { should be == 1 } + it 'adds a line to the end' do + execute + expect(editor.lines).to be == ['one', 'two', 'two', 'three', 'new'] + end + end + + context 'when there is a match' do + subject(:execute) { editor.append_line_if_missing('one', 'new') } + + it('returns the number of added lines') { should be == 0 } + it 'does not add any lines' do + expect { execute }.to_not change { editor.lines } + end + end + + it 'matches a Regexp' do + expect(editor.append_line_if_missing(/ee$/, 'new')).to be == 0 + expect(editor.append_line_if_missing(/^ee/, 'new')).to be == 1 + end + end + + describe '#remove_lines' do + context 'when there is no match' do + subject(:execute) { editor.remove_lines('missing') } + + it('returns the number of removed lines') { should be == 0 } + it 'does not remove any lines' do + expect { execute }.to_not change { editor.lines } + end + end + + context 'when there is a match' do + subject(:execute) { editor.remove_lines('two') } + + it('returns the number of removed lines') { should be == 2 } + it 'removes the matching lines' do + execute + expect(editor.lines).to be == ['one', 'three'] + end + end + + it 'matches a Regexp' do + expect(editor.remove_lines(/^ee/)).to be == 0 + expect(editor.remove_lines(/ee$/)).to be == 1 + end + end + + describe '#replace' do + context 'when there is no match' do + subject(:execute) { editor.replace('missing', 'new') } + + it('returns the number of changed lines') { should be == 0 } + it 'does not change any lines' do + expect { execute }.to_not change { editor.lines } + end + end + + context 'when there is a match' do + subject(:execute) { editor.replace('two', 'new') } + + it('returns the number of changed lines') { should be == 2 } + it 'replaces the matching portions' do + execute + expect(editor.lines).to be == ['one', 'new', 'new', 'three'] + end + end + + it 'matches a Regexp' do + expect(editor.replace(/^ee/, 'new')).to be == 0 + expect(editor.replace(/ee$/, 'new')).to be == 1 + expect(editor.lines).to be == ['one', 'two', 'two', 'thrnew'] + end + end + + describe '#replace_lines' do + context 'when there is no match' do + subject(:execute) { editor.replace_lines('missing', 'new') } + + it('returns the number of changed lines') { should be == 0 } + it 'does not change any lines' do + expect { execute }.to_not change { editor.lines } + end + end + + context 'when there is a match' do + subject(:execute) { editor.replace_lines('two', 'new') } + + it('returns the number of replaced lines') { should be == 2 } + it 'replaces the matching line' do + execute + expect(editor.lines).to be == ['one', 'new', 'new', 'three'] + end + end + + it 'matches a Regexp' do + expect(editor.replace_lines(/^ee/, 'new')).to be == 0 + expect(editor.replace_lines(/ee$/, 'new')).to be == 1 + expect(editor.lines).to be == ['one', 'two', 'two', 'new'] + end + end +end |