fix_protocol_tools 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/fixgrep ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ path = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include? path
5
+
6
+ require 'optparse'
7
+ require 'fix_protocol_tools'
8
+
9
+ raise "To be implemented"
10
+ #FixProtocolTools::Runner.new.grep!
data/bin/fixless ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ path = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include? path
5
+
6
+ require 'optparse'
7
+ require 'fix_protocol_tools'
8
+
9
+ FixProtocolTools::Runner.new.less!
@@ -0,0 +1,107 @@
1
+ require 'term/ansicolor'
2
+ require 'logger'
3
+ require 'fix_protocol_tools/specification/fix_specification'
4
+
5
+ module FixProtocolTools
6
+ class MessagesProcessor
7
+ include Term::ANSIColor
8
+ MESSAGE_DELIMITER = "\x01"
9
+
10
+ def initialize(options)
11
+ @spec = nil
12
+ @is_even_line = true
13
+ @output = init_output_chanel options
14
+ @grep = options[:grep]
15
+ end
16
+
17
+ def process()
18
+ buffer = nil
19
+
20
+ ARGF.each do |line|
21
+ line = line.gsub(/\r/, '').chomp
22
+ if buffer
23
+ buffer += line
24
+ if buffer =~ /8=FIX.*[A\x01]10=\d+/
25
+ process_line(buffer)
26
+ buffer = nil
27
+ end
28
+ else
29
+ if line =~ /8=FIX/ && !(line =~ /[A\x01]10=\d+/)
30
+ buffer = line
31
+ else
32
+ process_line(line)
33
+ end
34
+ end
35
+ end
36
+
37
+ process_line(buffer) if buffer
38
+
39
+ @output.close
40
+ end
41
+
42
+ private
43
+
44
+ def print_line(line)
45
+ @output.puts(@is_even_line ? green(line) : line)
46
+ @is_even_line = !@is_even_line
47
+ end
48
+
49
+ def process_line(line)
50
+ fields = fix_message_fields(line.gsub('^A', MESSAGE_DELIMITER))
51
+ return unless fields
52
+
53
+ @spec ||= resolve_specification(fields)
54
+ @output.puts(yellow(' =-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-= '))
55
+
56
+ fields.each do |field_id, value_id|
57
+ field_name = @spec.field_name(field_id) || field_id
58
+ field_name_padding = @spec.max_field_length - field_name.length - 2
59
+
60
+ print_line(format_line(field_id, field_name, field_name_padding, value_id))
61
+ end
62
+ end
63
+
64
+ def format_line(field_id, field_name, padding, value_id)
65
+ if @spec.message_type?(field_id)
66
+ formatted_row(field_id, value_id, field_name, red(@spec.message_type(value_id)), padding)
67
+ else
68
+ formatted_row(field_id, value_id, field_name, @spec.enum_value(field_id, value_id), padding)
69
+ end
70
+ end
71
+
72
+ def formatted_row(field_id, value_id, field_name, value_name, field_name_padding)
73
+ field_name + ' = '.rjust(field_name_padding) + value_name +
74
+ ' '.rjust(35 - value_name.length) +
75
+ field_id.rjust(5 - field_id.length) + ' = ' + value_id
76
+ end
77
+
78
+ def resolve_specification(fields)
79
+ fix_version = fields[0].last
80
+ Specification::Specification.new(fix_version)
81
+ end
82
+
83
+ def fix_message_fields(line)
84
+ start_index = line.index("8=FIX")
85
+ end_index = line.rindex(MESSAGE_DELIMITER)
86
+
87
+ if start_index || end_index
88
+ line[start_index, end_index].split(MESSAGE_DELIMITER).map do |pair|
89
+ pair.strip.split '='
90
+ end
91
+ else
92
+ nil
93
+ end
94
+ end
95
+
96
+ def init_output_chanel(options)
97
+ if options[:less]
98
+ cmd = 'less'
99
+ cmd += ' -r' if options[:color]
100
+ IO.popen(cmd, 'w')
101
+ else
102
+ STDOUT
103
+ end
104
+ end
105
+ end
106
+ end
107
+
@@ -0,0 +1,56 @@
1
+ require 'term/ansicolor'
2
+ require 'fix_protocol_tools/messages_processor'
3
+
4
+ Term::ANSIColor::coloring = STDOUT.isatty
5
+
6
+ module FixProtocolTools
7
+ class Runner
8
+
9
+ def less!
10
+ options = {:less => false, :color => false}
11
+ opt_parse = OptionParser.new do |opts|
12
+ opts.banner = "Usage: fixless [options] [fixlogfile]"
13
+
14
+ color(options, opts)
15
+ help(opts)
16
+
17
+ opts.on('-l', '--[no-]less', 'Use less command for output') do |color|
18
+ options[:less] = color
19
+ end
20
+ end
21
+
22
+ opt_parse.parse!
23
+
24
+ MessagesProcessor.new(options).process
25
+ end
26
+
27
+ def grep!
28
+ options = {:color => false}
29
+ opt_parse = OptionParser.new do |opts|
30
+ opts.banner = "Usage: fixgrep [options] [fixlogfile]"
31
+
32
+ color(opts, options)
33
+ help(opts)
34
+ end
35
+
36
+ opt_parse.parse!
37
+ MessagesProcessor.new(options).process
38
+ end
39
+
40
+ private
41
+
42
+ def help(opts)
43
+ opts.on('--help', '-h', 'Display help message') do
44
+ puts opts
45
+ exit
46
+ end
47
+ end
48
+
49
+ def color(options, opts)
50
+ opts.on('-c', '--[no-]color', 'Generate color output') do |color|
51
+ Term::ANSIColor::coloring = color
52
+ options[:color] = color
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,39 @@
1
+ require 'fix_protocol_tools/specification/specification_reader'
2
+
3
+ module FixProtocolTools::Specification
4
+ class Specification
5
+ attr_reader :max_field_length
6
+
7
+ def initialize(fix_version)
8
+ reader = Reader.read_specification(fix_version)
9
+
10
+ @enums = reader.enums
11
+ @fields = reader.fields
12
+ @message_types = reader.message_types
13
+ @max_field_length = reader.max_field_length
14
+ end
15
+
16
+ def field_name(field_number)
17
+ @fields[field_number]
18
+ end
19
+
20
+ def message_type?(tag)
21
+ tag == '35'
22
+ end
23
+
24
+ def message_type(tag35)
25
+ @message_types[tag35]
26
+ end
27
+
28
+
29
+ def enum_value(field, enum_id)
30
+ enum = @enums[field]
31
+
32
+ if enum and enum.has_key?(enum_id)
33
+ enum[enum_id]
34
+ else
35
+ enum_id
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,62 @@
1
+ require 'rexml/document'
2
+ require 'rexml/streamlistener'
3
+
4
+ module FixProtocolTools::Specification
5
+ class Reader
6
+ include REXML::StreamListener
7
+ SPECIFICATION_PATH = File.join(File.expand_path(File.dirname(__FILE__)), 'xml')
8
+
9
+ attr_reader :fields, :message_types, :enums, :max_field_length
10
+
11
+ def self.read_specification(fix_version)
12
+ reader = new
13
+
14
+ File.open(File.join(SPECIFICATION_PATH, fix_version.delete('.') + '.xml'), 'r') do |file|
15
+ REXML::Document.parse_stream(file, reader)
16
+ end
17
+
18
+ reader
19
+ end
20
+
21
+ def initialize
22
+ @message_types = {}
23
+ @fields = {}
24
+ @enums = Hash.new { |h, k| h[k] = {} }
25
+
26
+ @max_field_length = 0
27
+ end
28
+
29
+ def tag_start(tag_name, attrs)
30
+ if message?(attrs, tag_name)
31
+ @message_types[attrs['msgtype']] = attrs['name']
32
+ end
33
+
34
+ if field_definition?(attrs, tag_name)
35
+ @current_field = attrs['number']
36
+ @fields[attrs['number']] = attrs['name']
37
+ end
38
+
39
+ if enum_value?(attrs, tag_name)
40
+ @enums[@current_field][attrs['enum']] = attrs['description']
41
+ end
42
+
43
+ if attrs.has_key? 'name'
44
+ @max_field_length = [@max_field_length, attrs['name'].length].max
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def field_definition?(attrs, tag_name)
51
+ tag_name == 'field' && attrs.has_key?('number') && attrs.has_key?('name')
52
+ end
53
+
54
+ def enum_value?(attrs, tag_name)
55
+ tag_name == 'value' && attrs.has_key?('enum')
56
+ end
57
+
58
+ def message?(attrs, tag_name)
59
+ tag_name == 'message' && attrs.has_key?('name') != nil && attrs['msgtype'] != nil && attrs['msgcat'] != nil
60
+ end
61
+ end
62
+ end