ClsRuby 1.0.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 (71) hide show
  1. data/LICENSE +26 -0
  2. data/README +55 -0
  3. data/THANKS +0 -0
  4. data/docs/base_formatting_methods +89 -0
  5. data/docs/base_parsing_methods +79 -0
  6. data/docs/constructor_params +131 -0
  7. data/docs/examples/log_single_line_format +3 -0
  8. data/docs/examples/service_description +3 -0
  9. data/docs/examples/sms-hist +3 -0
  10. data/docs/examples/tag_any +3 -0
  11. data/docs/fragments/custom_tag_field.rb +20 -0
  12. data/docs/fragments/custom_tag_include.rb +21 -0
  13. data/docs/fragments/field.cls +2 -0
  14. data/docs/fragments/include.cls +4 -0
  15. data/docs/fragments/inherit_tag_params.rb +21 -0
  16. data/docs/fragments/message.cls +6 -0
  17. data/docs/fragments/tag_field.rb +24 -0
  18. data/docs/fragments/tag_message.rb +74 -0
  19. data/docs/fragments/tags_order.rb +41 -0
  20. data/docs/principles +402 -0
  21. data/docs/std_tags_short_description +278 -0
  22. data/docs/syntax +227 -0
  23. data/docs/why_cls +178 -0
  24. data/examples/hex_stream.txt +1 -0
  25. data/examples/log_single_line_formatter.rb +79 -0
  26. data/examples/service_description.day_time.cfg +11 -0
  27. data/examples/service_description.rb +119 -0
  28. data/examples/sms-hist.rb +164 -0
  29. data/examples/space_concat.txt +3 -0
  30. data/examples/tag_any.rb +28 -0
  31. data/lib/cls-ruby/basic_scalars.rb +270 -0
  32. data/lib/cls-ruby/constraints/one_of.rb +36 -0
  33. data/lib/cls-ruby/default_formatter.rb +50 -0
  34. data/lib/cls-ruby/ex.rb +121 -0
  35. data/lib/cls-ruby/formatter.rb +31 -0
  36. data/lib/cls-ruby/lexers/char_classifier.rb +157 -0
  37. data/lib/cls-ruby/lexers/first_stage.rb +112 -0
  38. data/lib/cls-ruby/lexers/lexer.rb +74 -0
  39. data/lib/cls-ruby/oneline_formatter.rb +35 -0
  40. data/lib/cls-ruby/parser.rb +249 -0
  41. data/lib/cls-ruby/tag.rb +428 -0
  42. data/lib/cls-ruby/tag_any.rb +111 -0
  43. data/lib/cls-ruby/tag_no_value.rb +55 -0
  44. data/lib/cls-ruby/tag_scalar.rb +197 -0
  45. data/lib/cls-ruby/tag_scalar_helpers.rb +70 -0
  46. data/lib/cls-ruby/tag_scalar_vector.rb +148 -0
  47. data/lib/cls-ruby/tag_vector_of_different_tags.rb +172 -0
  48. data/lib/cls-ruby/tag_vector_of_tags.rb +116 -0
  49. data/lib/cls-ruby/vector_of_tags_impl.rb +129 -0
  50. data/lib/cls-ruby.rb +5 -0
  51. data/tests/tc_child_tag.rb +51 -0
  52. data/tests/tc_constraint_one_of.rb +47 -0
  53. data/tests/tc_format_helper.rb +27 -0
  54. data/tests/tc_formatters.rb +125 -0
  55. data/tests/tc_lexer.rb +124 -0
  56. data/tests/tc_lexer_char_classifier.rb +121 -0
  57. data/tests/tc_lexer_first_stage.rb +72 -0
  58. data/tests/tc_parser_simple.rb +93 -0
  59. data/tests/tc_scalar_parsers.rb +189 -0
  60. data/tests/tc_tag.rb +68 -0
  61. data/tests/tc_tag_no_value.rb +46 -0
  62. data/tests/tc_tag_scalar_int.rb +83 -0
  63. data/tests/tc_tag_scalar_nonspace_string.rb +46 -0
  64. data/tests/tc_tag_scalar_string.rb +47 -0
  65. data/tests/tc_tag_scalar_vector_int.rb +88 -0
  66. data/tests/tc_tag_scalar_vector_string.rb +48 -0
  67. data/tests/tc_tag_scalar_vector_string_empty.rb +40 -0
  68. data/tests/tc_tag_vector_of_different_tags.rb +109 -0
  69. data/tests/tc_tag_vector_of_tags.rb +103 -0
  70. data/tests/ts_cls_ruby.rb +7 -0
  71. metadata +140 -0
@@ -0,0 +1,116 @@
1
+ #
2
+ # �����, ������� ��������� ��������� �� ������� ������ ������������������
3
+ # ���������� �����.
4
+ #
5
+
6
+ require 'cls-ruby/vector_of_tags_impl'
7
+
8
+ module ClsRuby
9
+
10
+ # �����, ������� ��������� ��������� �� ������� ������ ������������������
11
+ # ���������� �����.
12
+ #
13
+ # ��������, ���������� ���:
14
+ # {field {name <str>} {value <str>}}
15
+ # ��� ������ � ������� ��� ������ �����:
16
+ # class TagField < ClsRuby::TagNoValue
17
+ # Values = Struct.new( :name, :value )
18
+ #
19
+ # child_tag :name, ClsRuby::TagScalar,
20
+ # :format => ClsRuby::SCALAR_STRING,
21
+ # :mandatory => true
22
+ # child_tag :value, ClsRuby::TagScalar,
23
+ # :format => ClsRuby::SCALAR_STRING,
24
+ # :mandatory => true
25
+ #
26
+ # def value
27
+ # Values.new( @name.value, @value.value )
28
+ # end
29
+ # end
30
+ #
31
+ # ����� ��������� ��������� ������� �����, � ������� ��� {field}
32
+ # ����� ����������� ����� ������ ����. ��������:
33
+ # {message
34
+ # {name <str>}
35
+ # {field <TagField>}*
36
+ # }
37
+ #
38
+ # ��� ����, ����� �������� ������������ ��� ����� ��� ��������� �����
39
+ # TagField ����� ��������������� ����� TagVectorOfTags:
40
+ # class TagMessage < ClsRuby::TagNoValue
41
+ # child_tag :name, ClsRuby::TagScalar,
42
+ # :format => ClsRuby::SCALAR_STRING,
43
+ # :mandatory => true
44
+ # child_tag :field, ClsRuby::TagVectorOfTags,
45
+ # :type => TagField
46
+ # ...
47
+ # end
48
+ #
49
+ # ������� ������ TagVectorOfTags ������� � ���, ��� TagVectorOfTags ������
50
+ # ���� Proxy. �� ����������� ����������� ������� ������� ������ Tag �:
51
+ # - � ������ tag_on_start ������� ��������� ��������� ������� ���� ����,
52
+ # ������� ��� ����� ���������� :type (� ����������� ���� ������� ���
53
+ # ����� TagField), ����� ���� ������ ������������ ��� ��������� ���;
54
+ # - ������������ ������ tag_on_tag, tag_on_tok_*, tag_tags, tag_on_finish
55
+ # ���������� ����;
56
+ # - � ������ tag_on_finish, ���� ��������� ��� ��������� � tag_on_finish
57
+ # ��� ������, ��������� ��������� ��� � ������ ����������� ���������
58
+ # �����.
59
+ #
60
+ # ����� ������� �������� ������ ������ ����������� ��������� ����� �����
61
+ # �������� � ������� ������ nested_tags:
62
+ # class TagMessage < ClsRuby::TagNoValue
63
+ # ...
64
+ # Description = Struct.new( :name, :fields )
65
+ # ...
66
+ # def description
67
+ # fields = @field.nested_tags.inject( [] ) do |r, f| r << f.value; r end
68
+ # Description.new( @name.value, fields )
69
+ # end
70
+ # end
71
+ # ��� �� ����� ��������������� ������� TagVectorOfTags#collect_values:
72
+ # def description
73
+ # fields = @field.collect_values do |t| t.value end
74
+ # Description.new( @name.value, fields )
75
+ # end
76
+ # ��� ������� TagVectorOfTags#collect_values_by:
77
+ # def description
78
+ # fields = @field.collect_values_by( :value )
79
+ # Description.new( @name.value, fields )
80
+ # end
81
+ #
82
+ class TagVectorOfTags < Tag
83
+ include VectorOfTagsImplementation
84
+
85
+ # ������ � ������ ����������� ��������� �����.
86
+ attr_reader :nested_tags
87
+
88
+ # �����������.
89
+ #
90
+ # ������������� � ����������� ������ ���������� �����:
91
+ # [:type] ��� ���������� ����. ������ ���� ����������� ������
92
+ # �������������� � args.
93
+ #
94
+ def initialize( args = {} )
95
+ super( args )
96
+
97
+ @type = tag_params.fetch( :type, nil )
98
+ raise UndefinedTypeEx.new(
99
+ "undefined type of nested tags for '#{tag_name}'" ) unless @type
100
+ @nested_tags = []
101
+ @current = nil
102
+ end
103
+
104
+ # ������� �� ������ �������� ���� �� ������� ������.
105
+ #
106
+ # ������� ����� ��������� ��� � ������������ ����� ���.
107
+ def tag_on_start( name )
108
+ next_tag = @type.new( :name => name )
109
+ next_tag.tag_on_start( name )
110
+ @current = next_tag
111
+ end
112
+
113
+ end
114
+
115
+ end # module ClsRuby
116
+
@@ -0,0 +1,129 @@
1
+ #
2
+ # ������, ������� �������� ���������� ���������� ������� � �����
3
+ # ������� �����, ��� TagVectorOfTags � TagVectorOfDifferentTags.
4
+ #
5
+
6
+ module ClsRuby
7
+
8
+ module VectorOfTagsImplementation
9
+
10
+ # ��������� ��������� ��������� ��� � ������ ����������� ��������� �����.
11
+ def add_nested_tag( nested )
12
+ @nested_tags << nested
13
+ end
14
+
15
+ # ��������������� �����, ������� ��������� �������� ������ ��������
16
+ # �� ��������� �����.
17
+ #
18
+ # [block] ���� ����, ������� �������� ��������� ��� � ���������
19
+ # �� ���� ��������. ����������� �������� ������ ���� ������������
20
+ # ��������� �����.
21
+ #
22
+ # <b>����������</b>. ���� ��� ���������� �������� �� ���������� ����
23
+ # ��������� ������� � ���� ����� ��� ����������, �� ����� ���������������
24
+ # ��� �� ������� collect_values_by.
25
+ #
26
+ # :call-seq:
27
+ # collect_values() { |tag| ... } => Array
28
+ #
29
+ def collect_values( &block ) # :yields: tag
30
+ @nested_tags.inject( [] ) do |r, t| r << block.call(t) end
31
+ end
32
+
33
+ # ��������������� �����, ������� ��������� �������� ������ ��������
34
+ # �� ��������� �����.
35
+ #
36
+ # [method] ��� ������, ������� ����� ������� � ���������� ���� ���
37
+ # ���������� ��������.
38
+ #
39
+ # :call-seq:
40
+ # collect_values_by( method ) => Array
41
+ #
42
+ def collect_values_by( method )
43
+ collect_values do |t| t.send( method ) end
44
+ end
45
+
46
+ # �� ��������������!
47
+ def tag_add( child )
48
+ raise NotSupportedEx.new(
49
+ "tag_add not supported by TagVectorOfTags (tag '#{tag_name}')" )
50
+ end
51
+
52
+ # ��������� ������ �������� �����.
53
+ #
54
+ # ���������� �������� ������, ���� ���� ��������� ��� (��� ����������
55
+ # �������� ������ ��� � ������ ����). � ������ ���������� ���������� ����
56
+ # ����������� ���������� NotSupportedEx.
57
+ def tag_tags
58
+ raise NotSupportedEx.new(
59
+ "tag_tags not supported for TagVectorOfTags " +
60
+ "(tag '#{tag_name}')" ) unless @current
61
+
62
+ @current.tag_tags
63
+ end
64
+
65
+ # ���������� true, ���� ���� ���� �� ���� ����������� ��������� ���.
66
+ def tag_defined?
67
+ 0 != @nested_tags.size
68
+ end
69
+
70
+ # �������� ���������� ����.
71
+ #
72
+ # ��������� ��� � ���������, �������������� ��������.
73
+ def tag_reset
74
+ @nested_tags = []
75
+ @current = nil
76
+ super
77
+ end
78
+
79
+ # �������������� ����������� ���� � �������� �����.
80
+ #
81
+ # ���������� ����� ���� ������������ �� ������ ������ ��������� �����.
82
+ #
83
+ def tag_format( formatter )
84
+ @nested_tags.each do |nested| nested.tag_format( formatter ) end
85
+ end
86
+
87
+ # ������� �� ���������� �������� ���� �� ������� ������.
88
+ #
89
+ # ������������ ����� �������� ���������� ����. ���� ������ ��
90
+ # ��������, �� ��������� ��������� ��� � ������ ��������� �����.
91
+ def tag_on_finish
92
+ next_tag = @current; @current = nil
93
+
94
+ next_tag.tag_on_finish
95
+ @nested_tags << next_tag
96
+ end
97
+
98
+ # ������� �� ���������� ������� ��������� ���� �� ������� ������.
99
+ #
100
+ # ������������ ����� �������� ���������� ����.
101
+ def tag_on_tag( tag )
102
+ @current.tag_on_tag( tag )
103
+ end
104
+
105
+ # ������� �� ����� :tok_space.
106
+ #
107
+ # ������������ ����� �������� ���������� ����.
108
+ def tag_on_tok_space( token )
109
+ @current.tag_on_tok_space( token )
110
+ end
111
+
112
+ # ������� �� ����� :tok_nonspace.
113
+ #
114
+ # ������������ ����� �������� ���������� ����.
115
+ def tag_on_tok_nonspace( token )
116
+ @current.tag_on_tok_nonspace( token )
117
+ end
118
+
119
+ # ������� �� ����� :tok_string.
120
+ #
121
+ # ������������ ����� �������� ���������� ����.
122
+ def tag_on_tok_string( token )
123
+ @current.tag_on_tok_string( token )
124
+ end
125
+
126
+ end # module VectorOfTagsImplementation
127
+
128
+ end # module ClsRuby
129
+
data/lib/cls-ruby.rb ADDED
@@ -0,0 +1,5 @@
1
+ $:.unshift( File.dirname( __FILE__ ) )
2
+
3
+ require 'cls-ruby/tag'
4
+ require 'cls-ruby/parser'
5
+
@@ -0,0 +1,51 @@
1
+ $:.unshift( File.join( File.dirname( __FILE__ ), '../lib' ) )
2
+
3
+ require 'test/unit'
4
+
5
+ require 'cls-ruby/parser'
6
+ require 'cls-ruby/tag_scalar'
7
+
8
+ class TC_ChildTag < Test::Unit::TestCase
9
+ class TagParams < ClsRuby::Tag
10
+ Result = Struct.new( :min, :max, :password )
11
+
12
+ child_tag :min, ClsRuby::TagScalar,
13
+ :mandatory => true,
14
+ :format => ClsRuby::SCALAR_UINT,
15
+ :constraint => 1..100
16
+
17
+ child_tag :max, ClsRuby::TagScalar,
18
+ :mandatory => true,
19
+ :format => ClsRuby::SCALAR_UINT,
20
+ :constraint => 100..1000
21
+
22
+ child_tag :password, ClsRuby::TagScalar,
23
+ :format => ClsRuby::SCALAR_STRING
24
+
25
+ def initialize( params )
26
+ super( params.merge( :name => 'params' ) )
27
+ end
28
+
29
+ def value
30
+ Result.new( @min.value, @max.value, @password.value )
31
+ end
32
+ end
33
+
34
+ def setup
35
+ @tag = TagParams.new( {} )
36
+ end
37
+
38
+ def test_normal
39
+ assert_nothing_raised do
40
+ ClsRuby::parse_string(
41
+ '{params {password "abc"} {max 345} {min 12}}',
42
+ @tag )
43
+ end
44
+
45
+ assert_equal( 12, @tag.value.min )
46
+ assert_equal( 345, @tag.value.max )
47
+ assert_equal( "abc", @tag.value.password )
48
+ end
49
+
50
+ end
51
+
@@ -0,0 +1,47 @@
1
+ $:.unshift( File.join( File.dirname( __FILE__ ), '../lib' ) )
2
+
3
+ require 'test/unit'
4
+
5
+ require 'cls-ruby'
6
+ require 'cls-ruby/tag_scalar'
7
+ require 'cls-ruby/constraints/one_of'
8
+
9
+ class TC_ConstraintOneOf < Test::Unit::TestCase
10
+ ALLOWED_VALUES = [ 'user', 'root', 'observer', 'guest' ]
11
+ def initialize( *args )
12
+ super( *args )
13
+
14
+ @tag = ClsRuby::TagStringScalar.new(
15
+ :name => 'mode',
16
+ :mandatory => true,
17
+ :constraint => ClsRuby::Constraints::OneOf.new( *ALLOWED_VALUES ) )
18
+ end
19
+
20
+ def teardown
21
+ @tag.tag_reset
22
+ end
23
+
24
+ def test_allowed_values
25
+ ALLOWED_VALUES.each do |value|
26
+ @tag.tag_reset
27
+
28
+ s = "{mode \"#{value}\"}"
29
+ assert_nothing_raised( "parsing #{s}" ) do
30
+ ClsRuby::parse_string( s, @tag )
31
+ end
32
+ assert_equal( value, @tag.value )
33
+ end
34
+ end
35
+
36
+ def test_disallowed_values
37
+ ALLOWED_VALUES.each do |value|
38
+ @tag.tag_reset
39
+
40
+ s = "{mode \"!#{value}\"}"
41
+ assert_raise( ClsRuby::ParsingErrorEx, "parsing #{s}" ) do
42
+ ClsRuby::parse_string( s, @tag )
43
+ end
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,27 @@
1
+ $:.unshift( File.join( File.dirname( __FILE__ ), '../lib' ) )
2
+
3
+ require 'test/unit'
4
+
5
+ require 'cls-ruby/basic_scalars'
6
+
7
+ class TC_FormatHelper < Test::Unit::TestCase
8
+ def test_main
9
+ values = [
10
+ [ '', '' ],
11
+ [ 'hello', 'hello' ],
12
+ [ "\x000\x011", "\\x000\\x011" ],
13
+ [ "{}\\|\"\n\t\r", "\\{\\}\\\\\\|\\\"\\n\\t\\r" ]
14
+ ]
15
+
16
+ values.each do |pair|
17
+ assert_equal(
18
+ pair[1],
19
+ ClsRuby::FormatHelper::to_tok_nonspace( pair[0] ) )
20
+
21
+ assert_equal(
22
+ '"' + pair[1] + '"',
23
+ ClsRuby::FormatHelper::to_tok_string( pair[0] ) )
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,125 @@
1
+ $:.unshift( File.join( File.dirname( __FILE__ ), '../lib' ) )
2
+
3
+ require 'test/unit'
4
+
5
+ require 'cls-ruby'
6
+ require 'cls-ruby/default_formatter.rb'
7
+ require 'cls-ruby/oneline_formatter.rb'
8
+ require 'cls-ruby/tag_no_value'
9
+ require 'cls-ruby/tag_vector_of_tags'
10
+ require 'cls-ruby/tag_scalar'
11
+ require 'cls-ruby/tag_scalar_vector'
12
+
13
+ module FormatterTestPerformer
14
+ Field = Struct.new( :name, :type )
15
+ class TagField < ClsRuby::TagNoValue
16
+ mandatory_child_tag :name, ClsRuby::TagStringScalar
17
+ mandatory_child_tag :type, ClsRuby::TagScalar,
18
+ :format => ClsRuby::SCALAR_NONSPACE_STRING
19
+
20
+ default_tag_params :name => 'field'
21
+
22
+ def value
23
+ Field.new( @name.value, @type.value )
24
+ end
25
+ end
26
+
27
+ Message = Struct.new( :name, :priority, :fields )
28
+ class TagMessage < ClsRuby::TagScalar
29
+ child_tag :priority, ClsRuby::TagIntScalar
30
+ child_tag :field, ClsRuby::TagVectorOfTags, :type => TagField
31
+
32
+ default_tag_params :name => 'message',
33
+ :format => ClsRuby::SCALAR_NONSPACE_STRING
34
+
35
+ alias_method :inherited_value, :value
36
+ def value
37
+ Message.new(
38
+ inherited_value,
39
+ @priority.tag_defined? ? 0 : @priority.value,
40
+ @field.collect_values_by( :value ) )
41
+ end
42
+ end
43
+
44
+ Service = Struct.new( :name, :ips, :messages )
45
+ class TagService < ClsRuby::TagNoValue
46
+ mandatory_child_tag :name, ClsRuby::TagStringScalar
47
+ mandatory_child_tag :ips, ClsRuby::TagScalarVector,
48
+ :format => ClsRuby::SCALAR_NONSPACE_STRING
49
+ child_tag :message, ClsRuby::TagVectorOfTags,
50
+ :type => TagMessage
51
+
52
+ default_tag_params :name => 'service'
53
+
54
+ def value
55
+ Service.new(
56
+ @name.value,
57
+ @ips.value,
58
+ @message.collect_values_by( :value ) )
59
+ end
60
+ end
61
+
62
+ def test_main
63
+ data = <<DATA
64
+ {service
65
+ {ips localhost
66
+ www.dummy.com
67
+ 192.0.0.1
68
+ }
69
+ {name "Supper!" }
70
+ {message Init }
71
+ {message QueryInfo
72
+ {field {name "service"} {type String}}
73
+ {field {name "startDate"} {type TimeStamp}}
74
+ {field {name "finishDate"} {type TimeStamp}}
75
+ }
76
+ {message InitiateTransaction
77
+ {priority 2}
78
+ {field {name "trxId"} {type UUID}}
79
+ {field {name "service"} {type String}}
80
+ }
81
+ {message AbortTransaction
82
+ {priority 5}
83
+ {field {name "trxId"} {type UUID}}
84
+ }
85
+ }
86
+ DATA
87
+ original_tag = TagService.new
88
+
89
+ assert_nothing_raised do
90
+ ClsRuby::parse_string( data, original_tag )
91
+ end
92
+
93
+ formating_result = ''
94
+ original_tag.tag_format( @formatter_class.new( formating_result ) )
95
+
96
+ reparsed_tag = TagService.new
97
+ assert_nothing_raised do
98
+ ClsRuby::parse_string( formating_result, reparsed_tag )
99
+ end
100
+
101
+ assert_equal( original_tag.value, reparsed_tag.value )
102
+ end
103
+
104
+ end # module FormatterTestPerformer
105
+
106
+ class TC_DefaultFormatter < Test::Unit::TestCase
107
+ include FormatterTestPerformer
108
+
109
+ def initialize( *args )
110
+ super( *args )
111
+
112
+ @formatter_class = ClsRuby::DefaultFormatter
113
+ end
114
+ end
115
+
116
+ class TC_OneLineFormatter < Test::Unit::TestCase
117
+ include FormatterTestPerformer
118
+
119
+ def initialize( *args )
120
+ super( *args )
121
+
122
+ @formatter_class = ClsRuby::OneLineFormatter
123
+ end
124
+ end
125
+
data/tests/tc_lexer.rb ADDED
@@ -0,0 +1,124 @@
1
+ $:.unshift( File.join( File.dirname( __FILE__ ), '../lib' ) )
2
+
3
+ require 'stringio'
4
+ require 'test/unit'
5
+
6
+ require 'cls-ruby/lexers/lexer'
7
+
8
+ class TC_Lexer< Test::Unit::TestCase
9
+ EOF = ClsRuby::Lexers::Lexer::EOF
10
+
11
+ def test_empty
12
+ parse_and_compare( "", [] )
13
+ end
14
+
15
+ def test_simple
16
+ parse_and_compare( 'abc',
17
+ [
18
+ [ 'abc', :tok_nonspace ],
19
+ ] )
20
+ end
21
+
22
+ def test_sample_1
23
+ line = <<EOS
24
+ {smsc_map
25
+ {cprov some_name
26
+ {.priority 1 }
27
+ }
28
+ }
29
+ EOS
30
+ parse_and_compare( line,
31
+ [ [ '{', :tok_open_block ],
32
+ [ 'smsc_map', :tok_nonspace ],
33
+ [ "\n ", :tok_space ],
34
+ [ '{', :tok_open_block ],
35
+ [ 'cprov', :tok_nonspace ],
36
+ [ ' ', :tok_space ],
37
+ [ 'some_name', :tok_nonspace ],
38
+ [ "\n ", :tok_space ],
39
+ [ '{', :tok_open_block ],
40
+ [ '.priority', :tok_nonspace ],
41
+ [ ' ', :tok_space ],
42
+ [ '1', :tok_nonspace ],
43
+ [ ' ', :tok_space ],
44
+ [ '}', :tok_close_block ],
45
+ [ "\n ", :tok_space ],
46
+ [ '}', :tok_close_block ],
47
+ [ "\n", :tok_space ],
48
+ [ '}', :tok_close_block ],
49
+ [ "\n", :tok_space ] ] )
50
+ end
51
+
52
+ def test_sample_2
53
+ line = <<EOS
54
+ ||
55
+ || first
56
+ ||
57
+ {smsc_map
58
+ {simple}
59
+ {more_complex||single line comment
60
+ "with \\\\string\|value inside"
61
+ }
62
+ {cprov some_name
63
+ {.priority 1 }
64
+ }
65
+ || yet another
66
+ } || and another
67
+ || and yet another
68
+ EOS
69
+ parse_and_compare( line,
70
+ [ [ "||\n|| first\n||\n", :tok_space ],
71
+ [ '{', :tok_open_block ],
72
+ [ 'smsc_map', :tok_nonspace ],
73
+ [ "\n ", :tok_space ],
74
+ [ '{', :tok_open_block ],
75
+ [ 'simple', :tok_nonspace ],
76
+ [ '}', :tok_close_block ],
77
+ [ "\n ", :tok_space ],
78
+ [ '{', :tok_open_block ],
79
+ [ 'more_complex', :tok_nonspace ],
80
+ [ "||single line comment\n ", :tok_space ],
81
+ [ "with \\string|value inside", :tok_string ],
82
+ [ "\n ", :tok_space ],
83
+ [ '}', :tok_close_block ],
84
+ [ "\n ", :tok_space ],
85
+ [ '{', :tok_open_block ],
86
+ [ 'cprov', :tok_nonspace ],
87
+ [ ' ', :tok_space ],
88
+ [ 'some_name', :tok_nonspace ],
89
+ [ "\n ", :tok_space ],
90
+ [ '{', :tok_open_block ],
91
+ [ '.priority', :tok_nonspace ],
92
+ [ ' ', :tok_space ],
93
+ [ '1', :tok_nonspace ],
94
+ [ ' ', :tok_space ],
95
+ [ '}', :tok_close_block ],
96
+ [ "\n ", :tok_space ],
97
+ [ '}', :tok_close_block ],
98
+ [ "\n || yet another\n", :tok_space ],
99
+ [ '}', :tok_close_block ],
100
+ [ " || and another\n|| and yet another\n", :tok_space ] ] )
101
+ end
102
+
103
+ private
104
+ def parse_and_compare( source, expected )
105
+ result = parse_string( source )
106
+ assert_equal( expected.size, result.size,
107
+ "missmatched expected and result sizes" )
108
+ expected.each_with_index do |item, index|
109
+ assert_equal( item, result[ index ],
110
+ "missmatched item ##{index}" )
111
+ end
112
+ end
113
+
114
+ def parse_string( string )
115
+ result = []
116
+ lexer = ClsRuby::Lexers::Lexer.new( StringIO.new( string ), '-' )
117
+ while EOF != ( n = lexer.next )
118
+ result << n
119
+ end
120
+
121
+ result
122
+ end
123
+ end
124
+