summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Bandy <bandy.chris@gmail.com>2014-01-10 07:04:00 +0000
committerBryan McLellan <btm@getchef.com>2014-03-19 14:39:24 -0700
commit963e33beb327162dd03b8b4d37789a53914b8ba8 (patch)
treeb83e91b9176b0e34b744a8373f50f4f6705554bc
parent4c5eb3eeff27f58009cc45de18f97d27d9d1355c (diff)
downloadchef-963e33beb327162dd03b8b4d37789a53914b8ba8.tar.gz
CHEF-3714: New object dedicated to manipulating text
-rw-r--r--lib/chef/util/editor.rb92
-rw-r--r--spec/unit/util/editor_spec.rb152
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