ascii-data-tools 0.9
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.
- data/.gitignore +3 -0
- data/.rvmrc +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.GPL2 +339 -0
- data/README.rdoc +52 -0
- data/Rakefile +42 -0
- data/TODO +4 -0
- data/ascii-data-tools.gemspec +30 -0
- data/bin/ascii-data-cat +13 -0
- data/bin/ascii-data-edit +13 -0
- data/bin/ascii-data-norm +13 -0
- data/bin/ascii-data-qdiff +13 -0
- data/bin/ascii-data-tools-config +9 -0
- data/examples/big +10000 -0
- data/examples/built_in_records.gz +0 -0
- data/examples/slightly_modified_built_in_records.gz +0 -0
- data/features/ascii-data-cat.feature +110 -0
- data/features/ascii-data-edit.feature +91 -0
- data/features/ascii-data-qdiff.feature +54 -0
- data/features/encoding_decoding.feature +68 -0
- data/features/normaliser.feature +27 -0
- data/features/plugins.feature +73 -0
- data/features/record_recognition.feature +61 -0
- data/features/step_definitions/ascii-data-cat_steps.rb +48 -0
- data/features/step_definitions/ascii-data-edit_steps.rb +38 -0
- data/features/step_definitions/ascii-data-norm_steps.rb +7 -0
- data/features/step_definitions/ascii-data-qdiff_steps.rb +43 -0
- data/features/step_definitions/encoding_decoding_steps.rb +23 -0
- data/features/step_definitions/plugins_steps.rb +11 -0
- data/features/step_definitions/record_recognition_steps.rb +10 -0
- data/features/support/env.rb +5 -0
- data/lib/ascii-data-tools.rb +8 -0
- data/lib/ascii-data-tools/configuration.rb +169 -0
- data/lib/ascii-data-tools/configuration_printer.rb +38 -0
- data/lib/ascii-data-tools/controller.rb +123 -0
- data/lib/ascii-data-tools/discover.rb +19 -0
- data/lib/ascii-data-tools/external_programs.rb +23 -0
- data/lib/ascii-data-tools/filter.rb +148 -0
- data/lib/ascii-data-tools/filter/diffing.rb +139 -0
- data/lib/ascii-data-tools/formatting.rb +109 -0
- data/lib/ascii-data-tools/global_autodiscovery.rb +21 -0
- data/lib/ascii-data-tools/record.rb +50 -0
- data/lib/ascii-data-tools/record_type.rb +139 -0
- data/lib/ascii-data-tools/record_type/builder.rb +50 -0
- data/lib/ascii-data-tools/record_type/decoder.rb +77 -0
- data/lib/ascii-data-tools/record_type/encoder.rb +17 -0
- data/lib/ascii-data-tools/record_type/field.rb +168 -0
- data/lib/ascii-data-tools/record_type/normaliser.rb +38 -0
- data/lib/ascii-data-tools/ruby_extensions.rb +7 -0
- data/lib/ascii-data-tools/version.rb +3 -0
- data/spec/ascii-data-tools/configuration_printer_spec.rb +51 -0
- data/spec/ascii-data-tools/configuration_spec.rb +153 -0
- data/spec/ascii-data-tools/discover_spec.rb +8 -0
- data/spec/ascii-data-tools/filter/diffing_spec.rb +82 -0
- data/spec/ascii-data-tools/filter_spec.rb +107 -0
- data/spec/ascii-data-tools/formatting_spec.rb +106 -0
- data/spec/ascii-data-tools/record_spec.rb +49 -0
- data/spec/ascii-data-tools/record_type/builder_spec.rb +69 -0
- data/spec/ascii-data-tools/record_type/decoder_spec.rb +73 -0
- data/spec/ascii-data-tools/record_type/encoder_spec.rb +32 -0
- data/spec/ascii-data-tools/record_type/field_spec.rb +160 -0
- data/spec/ascii-data-tools/record_type/normaliser_spec.rb +25 -0
- data/spec/ascii-data-tools/record_type_spec.rb +175 -0
- data/spec/filter_helper.rb +24 -0
- data/spec/record_type_helpers.rb +8 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +5 -0
- metadata +196 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
Before do |scenario|
|
4
|
+
@output_stream = StringIO.new
|
5
|
+
@input_stream = StringIO.new
|
6
|
+
@user_feedback_stream = StringIO.new
|
7
|
+
|
8
|
+
@command_line = []
|
9
|
+
|
10
|
+
AsciiDataTools.record_types.clear
|
11
|
+
load 'ascii-data-tools/discover.rb'
|
12
|
+
@record_types = AsciiDataTools.record_types
|
13
|
+
end
|
14
|
+
|
15
|
+
Given /^a record stream containing$/ do |string|
|
16
|
+
@input_stream.string = string
|
17
|
+
end
|
18
|
+
|
19
|
+
Given /^file "([^\"]*)" containing$/ do |filename, string|
|
20
|
+
@record_source_filename = filename
|
21
|
+
@input_stream.string = string
|
22
|
+
end
|
23
|
+
|
24
|
+
When /^ascii-data-cat is invoked$/ do
|
25
|
+
AsciiDataTools::Controller::CatController.new(
|
26
|
+
:input_sources => [AsciiDataTools::InputSource.new(@record_source_filename, @input_stream)],
|
27
|
+
:output_stream => @output_stream,
|
28
|
+
:record_types => @record_types
|
29
|
+
).run
|
30
|
+
end
|
31
|
+
|
32
|
+
When /^([^\"]*) is invoked on a file "([^\"]*)" containing$/ do |executable, filename, string|
|
33
|
+
Given "file \"#{filename}\" containing", string
|
34
|
+
When "#{executable} is invoked"
|
35
|
+
end
|
36
|
+
|
37
|
+
When /^([^\"]*) is invoked on a record stream containing$/ do |executable, string|
|
38
|
+
Given "a record stream containing", string
|
39
|
+
When "#{executable} is invoked"
|
40
|
+
end
|
41
|
+
|
42
|
+
Then /^the following is printed out:$/ do |string|
|
43
|
+
@output_stream.string.should == string
|
44
|
+
end
|
45
|
+
|
46
|
+
Then /^the user receives the following feedback:$/ do |string|
|
47
|
+
@user_feedback_stream.string.should == string
|
48
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
When /^ascii-data-edit is invoked$/ do
|
2
|
+
AsciiDataTools::Controller::EditController.new(
|
3
|
+
:input_sources => [AsciiDataTools::InputSource.new(@record_source_filename, @input_stream)],
|
4
|
+
:output_stream => @output_stream,
|
5
|
+
:record_types => @record_types,
|
6
|
+
:user_feedback_stream => @user_feedback_stream,
|
7
|
+
:editor => lambda do |filenames|
|
8
|
+
edited_file = File.new(filenames.first)
|
9
|
+
edited_file.extend(AsciiDataTools::ExternalPrograms)
|
10
|
+
@text_prior_to_edit = edited_file.read
|
11
|
+
File.open(edited_file.path, 'w') {|f| f << @text_after_edit}
|
12
|
+
edited_file.modify_file_mtime_to(Time.now + 1)
|
13
|
+
end
|
14
|
+
).run
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^the output is successfully ascii\-edited to the following:$/ do |string|
|
18
|
+
@text_after_edit = string
|
19
|
+
When "ascii-data-edit is invoked"
|
20
|
+
end
|
21
|
+
|
22
|
+
When /^the output is ascii\-edited without alteration$/ do
|
23
|
+
AsciiDataTools::Controller::EditController.new(
|
24
|
+
:input_sources => [AsciiDataTools::InputSource.new(@record_source_filename, @input_stream)],
|
25
|
+
:output_stream => @output_stream,
|
26
|
+
:record_types => @record_types,
|
27
|
+
:user_feedback_stream => @user_feedback_stream,
|
28
|
+
:editor => lambda do |filenames| end
|
29
|
+
).run
|
30
|
+
end
|
31
|
+
|
32
|
+
Then /^the editor shows:$/ do |string|
|
33
|
+
@text_prior_to_edit.should == string
|
34
|
+
end
|
35
|
+
|
36
|
+
Then /^the encoded record stream contains:$/ do |string|
|
37
|
+
@output_stream.string.should == string
|
38
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
When /^ascii\-data\-norm is invoked$/ do
|
2
|
+
AsciiDataTools::Controller::NormalisationController.new(
|
3
|
+
:input_sources => [AsciiDataTools::InputSource.new(@record_source_filename, @input_stream)],
|
4
|
+
:output_stream => @output_stream,
|
5
|
+
:record_types => @record_types
|
6
|
+
).run
|
7
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Given /^streams containing$/ do |text|
|
2
|
+
@input_stream1 = StringIO.new
|
3
|
+
@input_stream2 = StringIO.new
|
4
|
+
|
5
|
+
text.split("\n").each do |line|
|
6
|
+
left_line, right_line = line.split("||").map(&:strip)
|
7
|
+
@input_stream1 << left_line.gsub('\n', "\n") unless left_line == "-" * left_line.length and not left_line.empty?
|
8
|
+
@input_stream2 << right_line.gsub('\n', "\n") unless right_line == "-" * right_line.length and not right_line.empty?
|
9
|
+
end
|
10
|
+
@input_stream1.rewind
|
11
|
+
@input_stream2.rewind
|
12
|
+
end
|
13
|
+
|
14
|
+
When /^ascii\-data\-qdiff is invoked on files containing:$/ do |string|
|
15
|
+
Given "streams containing", string
|
16
|
+
When "ascii-data-qdiff is invoked"
|
17
|
+
end
|
18
|
+
|
19
|
+
When /^ascii\-data\-qdiff is invoked$/ do
|
20
|
+
@actual_output1 = @actual_output2 = nil
|
21
|
+
AsciiDataTools::Controller::QDiffController.new(
|
22
|
+
:input_sources => [AsciiDataTools::InputSource.new(nil, @input_stream1),
|
23
|
+
AsciiDataTools::InputSource.new(nil, @input_stream2)],
|
24
|
+
:editor => lambda do |filenames|
|
25
|
+
@actual_output1 = File.read(filenames.first)
|
26
|
+
@actual_output2 = File.read(filenames.last)
|
27
|
+
end,
|
28
|
+
:output_stream => @output_stream,
|
29
|
+
:record_types => @record_types,
|
30
|
+
:user_feedback_stream => @user_feedback_stream
|
31
|
+
).run
|
32
|
+
end
|
33
|
+
|
34
|
+
Then /^the diffed result should be:$/ do |text|
|
35
|
+
expected_output1, expected_output2 = "", ""
|
36
|
+
text.split("\n").each do |line|
|
37
|
+
left_line, right_line = line.split("||").map(&:strip)
|
38
|
+
expected_output1 << left_line + "\n" unless left_line == "-" * left_line.length and not left_line.empty?
|
39
|
+
expected_output2 << right_line + "\n" unless right_line == "-" * right_line.length and not right_line.empty?
|
40
|
+
end
|
41
|
+
@actual_output1.should == expected_output1
|
42
|
+
@actual_output2.should == expected_output2
|
43
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
When /^I decode an encoded record "([^\"]*)" of type "([^\"]*)"$/ do |ascii_text, record_type_name|
|
2
|
+
ascii_text.gsub!('\\n', "\n")
|
3
|
+
@record = @record_types.find_by_name(record_type_name).decode(:ascii_string => ascii_text)
|
4
|
+
end
|
5
|
+
|
6
|
+
When /^I encode a record of type "([^\"]*)" and contents:$/ do |record_type_name, table|
|
7
|
+
record_type = @record_types.find_by_name(record_type_name)
|
8
|
+
values = table.hashes.collect {|hash| hash["field value"].gsub('\\n', "\n") }
|
9
|
+
@record = AsciiDataTools::Record::Record.new(record_type, values)
|
10
|
+
end
|
11
|
+
|
12
|
+
Then /^I should have a decoded record of type "([^\"]*)" and contents:$/ do |intended_record_type_name, table|
|
13
|
+
@record.type_name.should == intended_record_type_name
|
14
|
+
table.hashes.each do |hash|
|
15
|
+
expected_value = hash["field value"].gsub('\\n', "\n")
|
16
|
+
@record[hash["field name"]].should == expected_value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^I should have a encoded record "([^\"]*)"$/ do |expected_encoded_text|
|
21
|
+
expected_encoded_text.gsub!('\\n', "\n")
|
22
|
+
@record.encode.should == expected_encoded_text
|
23
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Given /^the following configuration:$/ do |code|
|
2
|
+
@record_types.instance_eval(code)
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^the record type configuration is printed$/ do
|
6
|
+
@configuration_printout = AsciiDataTools::RecordTypesConfigurationPrinter.for_record_types(@record_types).summary
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^it should look like this:$/ do |expected_string|
|
10
|
+
@configuration_printout.should == expected_string
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
When /^record "([^\"]*)" coming from ([^\"]*) is analysed$/ do |ascii_text, record_source_name|
|
2
|
+
record_source_name = nil if record_source_name == "unspecified"
|
3
|
+
ascii_text.gsub!('\\n', "\n")
|
4
|
+
type_determiner = AsciiDataTools::RecordType::TypeDeterminer.new(@record_types)
|
5
|
+
@type = type_determiner.determine_type_for(:ascii_string => ascii_text, :filename => record_source_name)
|
6
|
+
end
|
7
|
+
|
8
|
+
Then /^its type should be recognised as "([^\"]*)"$/ do |type_name|
|
9
|
+
@type.name.should == type_name
|
10
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'ascii-data-tools/ruby_extensions'
|
2
|
+
|
3
|
+
require 'ascii-data-tools/record'
|
4
|
+
require 'ascii-data-tools/record_type'
|
5
|
+
require 'ascii-data-tools/formatting'
|
6
|
+
require 'ascii-data-tools/configuration'
|
7
|
+
require 'ascii-data-tools/global_autodiscovery'
|
8
|
+
require 'ascii-data-tools/controller'
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'zlib'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
module AsciiDataTools
|
6
|
+
class Configuration
|
7
|
+
attr_reader :input_sources, :output_stream, :errors, :record_types, :editor, :user_feedback_stream
|
8
|
+
|
9
|
+
def initialize(arguments, overrides = {})
|
10
|
+
@arguments = arguments
|
11
|
+
@overrides = overrides
|
12
|
+
@errors = []
|
13
|
+
|
14
|
+
@opts = define_optionparser_configuration
|
15
|
+
remainder = parse(arguments)
|
16
|
+
|
17
|
+
@output_stream = overrides[:output_stream] || STDOUT
|
18
|
+
@input_sources = overrides[:input_sources] || make_input_streams(remainder, overrides)
|
19
|
+
@record_types = overrides[:record_types] || load_record_types
|
20
|
+
@editor = overrides[:editor]
|
21
|
+
@user_feedback_stream = overrides[:user_feedback_stream] || STDOUT
|
22
|
+
end
|
23
|
+
|
24
|
+
def valid?
|
25
|
+
@errors.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def error_info_with_usage
|
29
|
+
@errors.each {|error| puts error}
|
30
|
+
puts
|
31
|
+
puts @opts
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
def make_input_streams(remainder, overrides)
|
37
|
+
begin
|
38
|
+
return InputSourceFactory.new(overrides).input_sources_from(remainder)
|
39
|
+
rescue Exception => e
|
40
|
+
@errors << e.message
|
41
|
+
return nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def define_optionparser_configuration
|
46
|
+
OptionParser.new do |opts|
|
47
|
+
opts.banner = [
|
48
|
+
"Usage: #{File.basename($0)} [options] <input source>",
|
49
|
+
"An input source can be either a flat file or a gzipped flat file.",
|
50
|
+
@overrides[:input_pipe_accepted] ? "For this command, - (STDIN) is also allowed." : nil,
|
51
|
+
"\n"].compact.join("\n")
|
52
|
+
|
53
|
+
opts.separator ""
|
54
|
+
opts.separator "Other options:"
|
55
|
+
|
56
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
57
|
+
puts opts
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse(arguments)
|
64
|
+
begin
|
65
|
+
return @opts.parse(arguments)
|
66
|
+
rescue SystemExit => e
|
67
|
+
exit e.status
|
68
|
+
rescue Exception => e
|
69
|
+
@errors << e.message
|
70
|
+
return []
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def load_record_types
|
75
|
+
AsciiDataTools.autodiscover
|
76
|
+
AsciiDataTools.record_types
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class InputSourceFactory
|
81
|
+
def initialize(properties = {})
|
82
|
+
@expected_argument_number = properties[:expected_argument_number] || 1
|
83
|
+
@input_pipe_accepted = properties[:input_pipe_accepted].nil? ? true : properties[:input_pipe_accepted]
|
84
|
+
end
|
85
|
+
|
86
|
+
def input_sources_from(input_arguments)
|
87
|
+
validate_number_of input_arguments
|
88
|
+
return input_arguments.collect {|arg| make_input_source_from(arg)}
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
def validate_number_of(input_arguments)
|
93
|
+
raise "No input specified." if input_arguments.empty?
|
94
|
+
error_message = "#{input_arguments.size} input sources detected: #{input_arguments.inspect}. " +
|
95
|
+
"This command accepts #{@expected_argument_number} input source(s)."
|
96
|
+
raise error_message if input_arguments.length != @expected_argument_number
|
97
|
+
end
|
98
|
+
|
99
|
+
def make_input_source_from(input_argument)
|
100
|
+
if input_argument == "-"
|
101
|
+
if @input_pipe_accepted
|
102
|
+
return InputSource.new(nil, STDIN)
|
103
|
+
else
|
104
|
+
raise "STDIN not accepted for this command."
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
path_to_file = input_argument
|
109
|
+
raise "File #{path_to_file} does not exist!" unless File.exists?(path_to_file)
|
110
|
+
return InputSource.new(path_to_file, Zlib::GzipReader.open(path_to_file)) if path_to_file =~ /[.]gz$/
|
111
|
+
return InputSource.new(path_to_file, File.open(path_to_file))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class InputSource < Struct.new(:filename, :stream)
|
116
|
+
def read
|
117
|
+
stream.readline
|
118
|
+
end
|
119
|
+
|
120
|
+
def has_records?
|
121
|
+
not stream.eof?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class Editor
|
126
|
+
def initialize(&edit_command)
|
127
|
+
@tempfiles = {}
|
128
|
+
@preedit_mtimes = {}
|
129
|
+
@postedit_mtimes = {}
|
130
|
+
@edit_command = edit_command
|
131
|
+
end
|
132
|
+
|
133
|
+
def [](n)
|
134
|
+
@tempfiles[n] ||= Tempfile.new("ascii_tools")
|
135
|
+
end
|
136
|
+
|
137
|
+
def edit
|
138
|
+
close_all_tempfiles
|
139
|
+
save_preedit_mtimes
|
140
|
+
edit_files
|
141
|
+
save_postedit_mtimes
|
142
|
+
end
|
143
|
+
|
144
|
+
def changed?(n)
|
145
|
+
not @preedit_mtimes[n] == @postedit_mtimes[n]
|
146
|
+
end
|
147
|
+
|
148
|
+
protected
|
149
|
+
def close_all_tempfiles
|
150
|
+
@tempfiles.values.each {|f| f.close }
|
151
|
+
end
|
152
|
+
|
153
|
+
def save_preedit_mtimes
|
154
|
+
@tempfiles.each {|n, f| @preedit_mtimes[n] = File.mtime(f.path)}
|
155
|
+
end
|
156
|
+
|
157
|
+
def save_postedit_mtimes
|
158
|
+
@tempfiles.each {|n, f| @postedit_mtimes[n] = File.mtime(f.path)}
|
159
|
+
end
|
160
|
+
|
161
|
+
def edit_files
|
162
|
+
@edit_command[sorted_filenames]
|
163
|
+
end
|
164
|
+
|
165
|
+
def sorted_filenames
|
166
|
+
@tempfiles.sort.collect {|number, tempfile| tempfile.path}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'terminal-table/import'
|
2
|
+
|
3
|
+
module AsciiDataTools
|
4
|
+
class RecordTypesConfigurationPrinter
|
5
|
+
def initialize(presenter)
|
6
|
+
@presenter = presenter
|
7
|
+
end
|
8
|
+
|
9
|
+
def summary
|
10
|
+
table do |t|
|
11
|
+
t.headings = @presenter.headings
|
12
|
+
@presenter.record_type_summaries.each {|summary| t << summary}
|
13
|
+
end.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def for_record_types(record_types)
|
18
|
+
new(RecordTypesConfigurationPresenter.new(record_types))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class RecordTypesConfigurationPresenter
|
24
|
+
def initialize(record_types)
|
25
|
+
@record_types = record_types
|
26
|
+
end
|
27
|
+
|
28
|
+
def headings
|
29
|
+
["type name", "total length", "constraints", "normalised fields"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def record_type_summaries
|
33
|
+
@record_types.sort_by {|record_type| record_type.total_length_of_fields}.inject([]) do |summaries, record_type|
|
34
|
+
summaries << [record_type.name, record_type.total_length_of_fields, record_type.constraints_description, record_type.names_of_normalised_fields]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'ascii-data-tools/filter'
|
2
|
+
require 'ascii-data-tools/filter/diffing'
|
3
|
+
require 'ascii-data-tools/external_programs'
|
4
|
+
|
5
|
+
module AsciiDataTools
|
6
|
+
module Controller
|
7
|
+
class AbstractController
|
8
|
+
def initialize(configuration_or_command_line_arguments)
|
9
|
+
case configuration_or_command_line_arguments
|
10
|
+
when Hash then
|
11
|
+
@configuration = Configuration.new([], defaults.merge(configuration_or_command_line_arguments))
|
12
|
+
when Array then
|
13
|
+
@configuration = Configuration.new(configuration_or_command_line_arguments, defaults)
|
14
|
+
when Configuration then
|
15
|
+
@configuration = configuration_or_command_line_arguments
|
16
|
+
end
|
17
|
+
@configuration.error_info_with_usage unless @configuration.valid?
|
18
|
+
end
|
19
|
+
|
20
|
+
def type_determiner
|
21
|
+
@type_determiner ||= RecordType::TypeDeterminer.new(@configuration.record_types)
|
22
|
+
end
|
23
|
+
|
24
|
+
def run
|
25
|
+
raise "should be implemented!"
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
def input_source
|
30
|
+
@configuration.input_sources.first
|
31
|
+
end
|
32
|
+
|
33
|
+
def defaults
|
34
|
+
{:expected_argument_number => 1, :input_pipe_accepted => true}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class CatController < AbstractController
|
39
|
+
def run
|
40
|
+
formatting_filter = Filter::FormattingFilter.new(input_source.filename, type_determiner)
|
41
|
+
formatting_filter << input_source
|
42
|
+
formatting_filter.write(@configuration.output_stream)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class EditController < AbstractController
|
47
|
+
include ExternalPrograms
|
48
|
+
include Filter
|
49
|
+
|
50
|
+
def run
|
51
|
+
editor = Editor.new(&@configuration.editor)
|
52
|
+
formatting_filter = FormattingFilter.new(input_source.filename, type_determiner)
|
53
|
+
formatting_filter << input_source
|
54
|
+
|
55
|
+
formatting_filter.write(editor[0])
|
56
|
+
editor.edit
|
57
|
+
|
58
|
+
if not editor.changed?(0)
|
59
|
+
@configuration.user_feedback_stream.puts "The file is unmodified."
|
60
|
+
else
|
61
|
+
encoding_filter = Filter::Filter.new {|record| record.encode }
|
62
|
+
parsing_filter = ParsingFilter.new(@configuration.record_types)
|
63
|
+
encoding_filter << (parsing_filter << InputSource.new(nil, editor[0].open))
|
64
|
+
encoding_filter.write(output_stream)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
def output_stream
|
70
|
+
@configuration.output_stream == STDOUT ? File.open(input_source.filename, 'w') : @configuration.output_stream
|
71
|
+
end
|
72
|
+
|
73
|
+
def defaults
|
74
|
+
{:expected_argument_number => 1,
|
75
|
+
:input_pipe_accepted => false,
|
76
|
+
:editor => lambda {|filenames| edit_differences(filenames)} }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class NormalisationController < AbstractController
|
81
|
+
def run
|
82
|
+
normalising_filter = Filter::NormalisingFilter.new(input_source.filename, type_determiner)
|
83
|
+
normalising_filter << input_source
|
84
|
+
normalising_filter.write(@configuration.output_stream)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class QDiffController < AbstractController
|
89
|
+
include ExternalPrograms
|
90
|
+
include Filter
|
91
|
+
include Filter::Diffing
|
92
|
+
|
93
|
+
def run
|
94
|
+
editor = Editor.new(&@configuration.editor)
|
95
|
+
|
96
|
+
normaliser1 = NormalisingFilter.new( @configuration.input_sources[0].filename, type_determiner)
|
97
|
+
normaliser2 = NormalisingFilter.new( @configuration.input_sources[1].filename, type_determiner)
|
98
|
+
sorter1 = SortingFilter.new
|
99
|
+
sorter2 = SortingFilter.new
|
100
|
+
diff_executer = DiffExecutingFilter.new
|
101
|
+
diff_parser = DiffParsingFilter.new
|
102
|
+
diff_formatter = DiffFormattingFilter.new(type_determiner)
|
103
|
+
|
104
|
+
diff_formatter << (diff_parser << (diff_executer << [sorter1 << (normaliser1 << @configuration.input_sources[0]),
|
105
|
+
sorter2 << (normaliser2 << @configuration.input_sources[1])]))
|
106
|
+
|
107
|
+
begin
|
108
|
+
diff_formatter.write(editor[0], editor[1])
|
109
|
+
editor.edit
|
110
|
+
rescue StreamsEqualException => e
|
111
|
+
@configuration.user_feedback_stream.puts "The files are identical."
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
protected
|
116
|
+
def defaults
|
117
|
+
{:expected_argument_number => 2,
|
118
|
+
:input_pipe_accepted => false,
|
119
|
+
:editor => lambda {|filenames| edit_differences(filenames)} }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|