ascii-data-tools 0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|