vorax 0.4.2 → 5.0

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.
Files changed (56) hide show
  1. data/README.md +4 -29
  2. data/vorax.gemspec +3 -11
  3. metadata +4 -92
  4. data/.rspec +0 -1
  5. data/Rakefile +0 -30
  6. data/lib/vorax.rb +0 -60
  7. data/lib/vorax/base_funnel.rb +0 -30
  8. data/lib/vorax/output/html_convertor.rb +0 -120
  9. data/lib/vorax/output/html_funnel.rb +0 -79
  10. data/lib/vorax/output/pagezip_convertor.rb +0 -20
  11. data/lib/vorax/output/tablezip_convertor.rb +0 -22
  12. data/lib/vorax/output/vertical_convertor.rb +0 -53
  13. data/lib/vorax/output/zip_convertor.rb +0 -117
  14. data/lib/vorax/parser/argument.rb~ +0 -125
  15. data/lib/vorax/parser/conn_string.rb +0 -104
  16. data/lib/vorax/parser/grammars/alias.rb +0 -904
  17. data/lib/vorax/parser/grammars/alias.rl +0 -138
  18. data/lib/vorax/parser/grammars/column.rb +0 -454
  19. data/lib/vorax/parser/grammars/column.rl +0 -64
  20. data/lib/vorax/parser/grammars/common.rl +0 -107
  21. data/lib/vorax/parser/grammars/declare.rb +0 -9606
  22. data/lib/vorax/parser/grammars/declare.rl +0 -160
  23. data/lib/vorax/parser/grammars/for_block.rb +0 -440
  24. data/lib/vorax/parser/grammars/for_block.rl +0 -73
  25. data/lib/vorax/parser/grammars/plsql_def.rb +0 -539
  26. data/lib/vorax/parser/grammars/plsql_def.rl +0 -73
  27. data/lib/vorax/parser/grammars/statement.rb +0 -925
  28. data/lib/vorax/parser/grammars/statement.rl +0 -83
  29. data/lib/vorax/parser/parser.rb +0 -344
  30. data/lib/vorax/parser/plsql_structure.rb +0 -222
  31. data/lib/vorax/parser/plsql_walker.rb +0 -143
  32. data/lib/vorax/parser/statement_inspector.rb~ +0 -52
  33. data/lib/vorax/parser/stmt_inspector.rb +0 -78
  34. data/lib/vorax/parser/target_ref.rb +0 -110
  35. data/lib/vorax/sqlplus.rb +0 -273
  36. data/lib/vorax/version.rb +0 -7
  37. data/lib/vorax/vorax_io.rb +0 -70
  38. data/spec/column_spec.rb +0 -40
  39. data/spec/conn_string_spec.rb +0 -53
  40. data/spec/declare_spec.rb +0 -281
  41. data/spec/pagezip_spec.rb +0 -153
  42. data/spec/parser_spec.rb +0 -352
  43. data/spec/plsql_structure_spec.rb +0 -68
  44. data/spec/spec_helper.rb +0 -13
  45. data/spec/sql/create_objects.sql +0 -69
  46. data/spec/sql/dbms_crypto.spc +0 -339
  47. data/spec/sql/dbms_stats.spc +0 -4097
  48. data/spec/sql/drop_user.sql +0 -10
  49. data/spec/sql/muci.spc +0 -26
  50. data/spec/sql/setup_user.sql +0 -22
  51. data/spec/sql/test.fnc +0 -12
  52. data/spec/sql/test.pkg +0 -83
  53. data/spec/sqlplus_spec.rb +0 -52
  54. data/spec/stmt_inspector_spec.rb +0 -96
  55. data/spec/tablezip_spec.rb +0 -111
  56. data/spec/vertical_spec.rb +0 -150
@@ -1,79 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'nokogiri'
4
-
5
- module Vorax
6
-
7
- # A namespace for everything related to the sqlplus output processing.
8
- module Output
9
-
10
- # A special type of funnel to work with HTML convertors.
11
- class HTMLFunnel < BaseFunnel
12
-
13
- # Creates a new HTML funnel.
14
- #
15
- # @param convertor [HTMLConvertor] the convertor to be used
16
- # to transform the HTML content.
17
- def initialize(convertor)
18
- @tail = ''
19
- @parser = Nokogiri::HTML::SAX::PushParser.new(convertor)
20
- end
21
-
22
- # Put the html content into the funnel.
23
- #
24
- # @param text [String] a chunk of HTML text
25
- def write(text)
26
- if text && !text.empty?
27
- @parser.write text
28
- if @parser.document.should_spit_text?
29
- @tail << text
30
- # just to be sure we don't have stale text after
31
- # the last end tag
32
- ping
33
- end
34
- end
35
- end
36
-
37
- # Get the formatted text from the funnel, as it is transformed
38
- # by the buddy convertor.
39
- #
40
- # @return the formatted text
41
- def read
42
- @parser.document.io.rewind
43
- chunk = @parser.document.io.read
44
- @parser.document.io.truncate(0)
45
- @parser.document.io.seek(0)
46
- return chunk
47
- end
48
-
49
- private
50
-
51
- # This is a workaround. The Nokogiri pull parser doesn't spit anything
52
- # if there's no endding tag. For example, if "<p>Text" is given, "Text" will not
53
- # be spit because the end "</p>" is missing. In sqlplus this is common
54
- # especially for "prompt" or "accept" commands which spit output without
55
- # enclosing the text in any tags. The main problem is ACCEPT, where VoraX
56
- # will wait for users input, but the prompt will not be shown which will
57
- # make the poor user confused. The solution is to force a random tag into
58
- # the HTML input stream so that the parser to move along.
59
- def ping
60
- unless @tail.empty?
61
- # be carefull not to ping into incomplete tags
62
- last_open_tag_position = (@tail.rindex('<') || -1)
63
- last_close_tag_position = (@tail.rindex('>') || -1)
64
- last_open_entity_position = (@tail.rindex('&') || -1)
65
- last_close_entity_position = (@tail.rindex(';') || -1)
66
- hwm = [last_close_tag_position, last_close_entity_position].max
67
- @tail = @tail[hwm + 1 .. -1] if hwm >= 0
68
- if last_close_tag_position >= last_open_tag_position &&
69
- last_close_entity_position >= last_open_entity_position
70
- @parser << "<#{HTMLConvertor.ping_tag}/>"
71
- end
72
- end
73
- end
74
-
75
- end
76
-
77
- end
78
-
79
- end
@@ -1,20 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module Vorax
4
- module Output
5
-
6
- # A convertor used to compress every page returned by sqlplus when executing
7
- # a query.
8
- class PagezipConvertor < ZipConvertor
9
-
10
- # @see ZipConvertor.should_spit?
11
- def should_spit?(end_tag)
12
- ("table" == end_tag) ||
13
- ("th" == end_tag && rows.size > 0)
14
- end
15
-
16
- end
17
-
18
- end
19
- end
20
-
@@ -1,22 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module Vorax
4
-
5
- module Output
6
-
7
- # A convertor used to compress every HTML TABLE from the
8
- # sqlplus output.
9
- class TablezipConvertor < ZipConvertor
10
-
11
- # see ZipConvertor.should_spit?
12
- def should_spit?(current_tag)
13
- current_tag == "table"
14
- end
15
-
16
- end
17
-
18
- end
19
-
20
- end
21
-
22
-
@@ -1,53 +0,0 @@
1
- # encoding: UTF-8
2
- module Vorax
3
- module Output
4
-
5
- class VerticalConvertor < HTMLConvertor
6
-
7
- def initialize()
8
- super()
9
- reset_props()
10
- end
11
-
12
- def end_element name
13
- super(name)
14
- @io << "\n" if ['br', 'p'].include?(name)
15
- if "th" == name and @collect_columns
16
- column = @text.strip
17
- @columns << column
18
- @th_length = [column.length, @th_length].max
19
- end
20
- @values << @text.strip if "td" == name
21
- if "tr" == name && (not @values.empty?)
22
- @columns = Array.new(@values.size, "") if @columns.empty?
23
- @columns.each_with_index do |column, i|
24
- value = HTMLConvertor.ml_indent(@values[i], @th_length + 3)
25
- @io.print("#{column.ljust(@th_length)} : #{value}\n")
26
- end
27
- @values.clear
28
- @collect_columns = false
29
- print_row_separator
30
- end
31
- @text.clear unless HTMLConvertor.ping_tag == name
32
- reset_props() if name == "table"
33
- end
34
-
35
- def print_row_separator
36
- @separator ||= '-' * 60
37
- @io.print("#{'-' * 60}\n")
38
- end
39
-
40
- private
41
-
42
- def reset_props
43
- @columns = []
44
- @values = []
45
- @th_length = 0
46
- @text = ""
47
- @collect_columns = true
48
- end
49
-
50
- end
51
-
52
- end
53
- end
@@ -1,117 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module Vorax
4
-
5
- module Output
6
-
7
- # A special type of HTML convertor used for compressing HTML tables. This is an
8
- # abstract class and every convertor which needs compressing utilities must
9
- # inherit from this class.
10
- class ZipConvertor < HTMLConvertor
11
-
12
- attr_reader :rows, :last_close_tag, :last_open_tag
13
-
14
- # Create a new ZipConvertor.
15
- def initialize()
16
- super()
17
- reset_props()
18
- end
19
-
20
- # @see HTMLConvertor.start_hook
21
- def start_hook name, attrs = []
22
- @last_open_tag[:name] = name
23
- @last_open_tag[:attrs] = attrs
24
- end
25
-
26
- # @see HTMLConvertor.end_hook
27
- def end_hook name
28
- @io << "\n" if ['br', 'p'].include?(name)
29
- @record << {:text => text.strip,
30
- :is_column => ("th" == name),
31
- :align => get_align(@last_open_tag)} if ["td", "th"].include?(name)
32
- if "tr" == name
33
- @rows << @record.dup
34
- @record.clear
35
- end
36
- if should_spit?(name)
37
- spit
38
- @rows.clear
39
- end
40
- text.clear unless HTMLConvertor.ping_tag == name
41
- @last_close_tag.clear
42
- @last_close_tag << name
43
- reset_props() if "table" == name
44
- end
45
-
46
- # A method which tells if the accumulated compressed text should
47
- # be spit or not. This is the only method which must be implemented
48
- # into subclasses.
49
- #
50
- # @param name [String] the end HTML tag
51
- def should_spit?(name)
52
- raise RuntimeError.new "Implement me"
53
- end
54
-
55
- private
56
-
57
- def columns_layout
58
- layout = []
59
- (0..@rows.first.size-1).each do |i|
60
- width = @rows.inject(0) do |result, element|
61
- [result, HTMLConvertor.ml_width(element[i][:text])].max
62
- end
63
- first_data_row = @rows.detect { |row| row[i][:is_column] == false }
64
- align = first_data_row[i][:align] if first_data_row
65
- layout << {:width => width, :align => (align && align == "right" ? "rjust" : "ljust")}
66
- end
67
- layout
68
- end
69
-
70
- def separator(layout)
71
- # spit separator
72
- layout.each_with_index do |column, i|
73
- @io << "-" * column[:width]
74
- @io << (i == layout.size - 1 ? "\n" : " ")
75
- end
76
- end
77
-
78
- def spit
79
- layout = columns_layout
80
- # spit records
81
- @rows.each do |record|
82
- max_height = record.inject(0) { |result, element| [result, HTMLConvertor.ml_count(element[:text])].max }
83
- (0..max_height).each do |j|
84
- layout.length.times do |i|
85
- @io << "\n" if record[i][:is_column] && i == 0 && @first_spit == false
86
- @first_spit = false
87
- @io << HTMLConvertor.ml_segment(record[i][:text], j).send(layout[i][:align], layout[i][:width])
88
- @io << (i == layout.size - 1 ? "\n" : " ")
89
- separator(layout) if i == layout.size - 1 && record[i][:is_column]
90
- end
91
- end
92
- end
93
- end
94
-
95
- def get_align(tag)
96
- attrs = tag[:attrs]
97
- if attrs
98
- align_pair = attrs.find { |pair| pair[0] == "align" }
99
- return align_pair[1] if align_pair
100
- end
101
- end
102
-
103
- def reset_props
104
- @record = []
105
- @rows = []
106
- @last_open_tag = {:name => '', :attrs => []}
107
- @last_close_tag = ''
108
- @first_spit = true
109
- end
110
-
111
- end
112
-
113
- end
114
-
115
- end
116
-
117
-
@@ -1,125 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Vorax
4
-
5
- module Parser
6
-
7
- # Given a statement and a position we want to see if on that position we should
8
- # provide code completion for an argument
9
- class Argument
10
-
11
- def initialize(statement)
12
- @stmt = statement
13
- # interesting points to search within statement
14
- @marks = [BEGIN_PLSQL_SPECIAL_QUOTING, BEGIN_QUOTING,
15
- CLOSE_PARAN, OPEN_PARAN, ANY]
16
- # level referes to open/close brackets
17
- @level = 0
18
- end
19
-
20
- # the function/procedure which owns the argument at the
21
- # provided position
22
- def belongs_to(position = @stmt.length)
23
- @belongs_to = ''
24
- stmt = @stmt[(0...position)]
25
- # remove all comments
26
- stmt = Parser::Comment.new.remove_all(stmt)
27
- stmt.reverse!
28
- @ss = StringScanner.new(stmt)
29
- consume
30
- return @belongs_to
31
- end
32
-
33
- private
34
-
35
- def consume
36
- while !@ss.eos?
37
- @ss.skip_until(/#{@marks.join('|')}/im)
38
-
39
- process_plsql_quoting
40
- process_double_quotes
41
- process_single_quotes
42
- process_close_paran
43
- process_open_paran
44
-
45
- p @ss.rest
46
- gets
47
- end
48
- end
49
-
50
- def process_plsql_quoting
51
- # pay attention, is reveresed
52
- if @ss.matched =~ /'\]/
53
- @ss.skip_until(/\['q/)
54
- p 'a intrat'
55
- end
56
- #@ss.skip_until(/\{'q/) if @ss.matched =~ /'\}/
57
- #@ss.skip_until(/\('q/) if @ss.matched =~ /'\)/
58
- #@ss.skip_until(/\>'q/) if @ss.matched =~ /'\</
59
- end
60
-
61
- def process_double_quotes
62
- @ss.skip_until(/"/) if @ss.matched == '"'
63
- end
64
-
65
- def process_single_quotes
66
- if @ss.matched == "'"
67
- begin
68
- @ss.skip_until(/\'+/)
69
- end while (@ss.matched != "'" && !@ss.eos?)
70
- end
71
- end
72
-
73
- def process_close_paran
74
- if @ss.matched =~ /#{CLOSE_PARAN}/
75
- @level += 1
76
- end
77
- end
78
-
79
- def process_open_paran
80
- if @ss.matched =~ /#{OPEN_PARAN}/
81
- if @level == 0
82
- extract_module
83
- else
84
- @level -= 1
85
- @ss.terminate if @level < 0 #give up, it's an invalid statement
86
- end
87
- end
88
- end
89
-
90
- def extract_module
91
- while !@ss.eos?
92
- # consume leading whitspaces
93
- @ss.scan(/\s*/)
94
- if @ss.check(/"/) == '"'
95
- # we have a quoted identifier
96
- @belongs_to << @ss.scan(/"/)
97
- @belongs_to << @ss.scan_until(/"/)
98
- else
99
- # unquoted identifier
100
- @belongs_to << @ss.scan(/\S+/)
101
- end
102
- # consume trailing whitespaces
103
- @ss.scan(/\s*/)
104
-
105
- # might be a dblink
106
- if @ss.check(/@/) == '@'
107
- @belongs_to << @ss.scan(/@/)
108
- next
109
- end
110
-
111
- # might be package or a owner
112
- if @ss.check(/\./) == '.'
113
- @belongs_to << @ss.scan(/\./)
114
- next
115
- end
116
- @ss.terminate
117
- end
118
- @belongs_to.reverse!
119
- end
120
-
121
- end
122
-
123
- end
124
-
125
- end
@@ -1,104 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'strscan'
4
-
5
- module Vorax
6
-
7
- module Parser
8
-
9
- # A class used to parse a connection string.
10
- class ConnString
11
-
12
- # Parse the given connection string.
13
- #
14
- # @return [Hash] a hash with the following keys:
15
- #
16
- # :user => the username,
17
- # :password => the password,
18
- # :db => the target database,
19
- # :role => sysdba, sysasm or sysoper (if that's the case),
20
- # :prompt_for => when some pieces are missing (e.g. password), the corresponding keys from above is put here
21
- def parse(cstr)
22
- # well known connection strings:
23
- # - user => just the password will be prompted
24
- # - user/pwd
25
- # - user@db => just the password will be prompted
26
- # - user/pwd@db [as sysdba|sysoper|sysasm]
27
- # - /
28
- # - / [as sysdba|sysoper|sysasm}
29
- # - /@db => use wallet
30
- Vorax::debug("parse connection string #{cstr.inspect}")
31
- result = {:user => '', :password => '', :db => '', :role => '', :prompt_for => nil}
32
- input = cstr.strip
33
- scanner = StringScanner.new(input)
34
- result[:user] = unquoted_scan(scanner, /[@\/]/)
35
- has_pwd_slash = false
36
-
37
- if scanner.matched?
38
- # we have a @ or a / in our connection string
39
- result[:user].chop!
40
- if scanner.matched == "/"
41
- has_pwd_slash = true
42
- result[:password] = unquoted_scan(scanner, /@/)
43
- if scanner.matched?
44
- # there is a "@" so we know where to stop to extract the pwd
45
- result[:password].chop!
46
- extract_db(scanner, result)
47
- else
48
- # there's no "@" so assume everything to be the password
49
- # except for the role
50
- result[:password] = scanner.scan_until(/\z/)
51
- extract_role(result, :password)
52
- end
53
- elsif scanner.matched == "@"
54
- extract_db(scanner, result)
55
- end
56
- else
57
- # we don't have a @ or a / in our connection string
58
- result[:user] = input
59
- end
60
- result[:user] = strip_quotes(result[:user])
61
- result[:password] = strip_quotes(result[:password])
62
- if result[:user].empty? && result[:password].empty? && has_pwd_slash
63
- # assume OS authentication
64
- result[:prompt_for] = nil
65
- else
66
- if result[:user].empty?
67
- result[:prompt_for] = :user
68
- elsif (not result[:user].empty?) && result[:password].empty?
69
- result[:prompt_for] = :password
70
- end
71
- end
72
- result
73
- end
74
-
75
- private
76
-
77
- def strip_quotes(text)
78
- text.gsub(/\A"|"\z/, '')
79
- end
80
-
81
- def extract_db(scanner, cstr_hash)
82
- cstr_hash[:db] = scanner.scan_until(/\z/)
83
- extract_role(cstr_hash, :db)
84
- end
85
-
86
- def extract_role(cstr_hash, from_attr)
87
- cstr_hash[from_attr].sub!(/\s+as\s+(sysdba|sysoper|sysasm)\z/i, '')
88
- cstr_hash[:role] = $1.downcase if $1
89
- end
90
-
91
- def unquoted_scan(scanner, pattern)
92
- result = ''
93
- begin
94
- fragment = scanner.scan_until(pattern)
95
- result << fragment if fragment
96
- end while fragment && result.count('"').odd? # go on if between quotes
97
- result
98
- end
99
-
100
- end
101
-
102
- end
103
-
104
- end