dolos 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8a83a078e5fa82aa8f6d28f3315597937b84c604d59e18f177a950594860e93
4
- data.tar.gz: bccf5fc9390189e43ef9c785baeaf93b85e00d1ce480c63057cf0cc26c468050
3
+ metadata.gz: bdfe6ab9b41e2783d7a0f6fa530bccf44cecc1aaaf2dff900bc346ef980d8fef
4
+ data.tar.gz: 29ee6fd6ff4bdc45a8d165a54e5a0a6bc57d3ae7068a60049d00385b37011fa7
5
5
  SHA512:
6
- metadata.gz: 75fcc5acf6a6dfbd4eeaf7493f9f82a3d31b5d6b61c64f2d9ee3f6f7fe8856fa1392866cbde95ba12bdb06155f07ed7c9cfe46c24f4353c111bf3782f6033289
7
- data.tar.gz: '0608ddcb140a18c1d156ae8729f4c998b1abe4b257be8e02dddff796a3e7d861892ddfebcc6f54b744e9b03d381ed029ad81954b2ff484cc2621d5b7f804d3cb'
6
+ metadata.gz: 239dcd2a22ae2bcbd85e2915e28fe67eec4f0e75e9d7c7e4668ec930b30781cac256628833c8f5ca19cdafec1d31642098b27e5ba5a83c43e0abe08ae1277766
7
+ data.tar.gz: 0c5698dd2cd7b91b9861125e6306ba99a7406bcaf4b1314eac5218fdc789235cc91d3794c67f0f82ff9cf32956b52f788e1c20607215f04586919a3988e75dad
data/README.md CHANGED
@@ -23,30 +23,34 @@ require 'dolos'
23
23
  include Dolos
24
24
 
25
25
  ws = c(" ")
26
- parser = c("Parsers") >> ws >> c("are") >> ws >> c("great!")
26
+ parser = c("Parsers") & ws & c("are") & ws & c("great!")
27
27
  parser.run("Parsers are great!") # <Result::Success>
28
28
 
29
29
  greeter = c("Hello")
30
- greet_and_speak = greeter >> c(", ") >> parser
30
+ greet_and_speak = greeter & c(", ") & parser
31
31
  greet_and_speak.run("Hello, Parsers are great!") # <Result::Success>
32
32
  ```
33
33
 
34
34
  ### Letter address parser example
35
+
35
36
  ```ruby
36
37
  require 'dolos'
37
38
  require 'dolos_common_parsers/common_parsers'
38
39
 
40
+ include Dolos
41
+ # frozen_string_literal: true
42
+ require_relative 'dolos'
43
+ require_relative 'dolos_common_parsers/common_parsers'
44
+
39
45
  include Dolos
40
46
 
41
47
  # Include common parsers
42
- # In future this can be more structured,
43
- # moved them to separate module to prevent breaking changes
48
+ # In future this can be more structured, moved them to separate module to prevent breaking changes
44
49
  include Dolos::CommonParsers
45
50
 
46
51
  # Library usage example
47
52
  # Parse out a name and address from a letter
48
- # For higher difficulty, we will not split this into multiple lines,
49
- # but instead parse it all at once
53
+ # For higher difficulty, we will not split this into multiple lines, but instead parse it all at once
50
54
  letter = <<-LETTER
51
55
  Mr. Vardeniui Pavardeniui
52
56
  AB „Lietuvos Paštas“
@@ -63,12 +67,12 @@ alpha_with_lt = char_in("ąčęėįšųūžĄČĘĖĮŠŲŪŽ") | alpha
63
67
 
64
68
  # Capture all letters in a row and join them,
65
69
  # because they are captured as elements of array by each alpha_with_lt parser.
66
- first_name = alpha_with_lt.rep.capture!.map(&:join)
67
- last_name = alpha_with_lt.rep.capture!.map(&:join)
70
+ first_name = alpha_with_lt.rep.map(&:join).capture!
71
+ last_name = alpha_with_lt.rep.map(&:join).capture!
68
72
 
69
73
  # Combine first line parsers
70
74
  # Consume zero or more whitespace, after that honorific must follow and so on
71
- name_line = ws.rep0 >> honorific >> first_name >> ws >> last_name >> eol
75
+ name_line = ws.rep0 & honorific & first_name & ws & last_name & eol
72
76
 
73
77
  # Next line is company info
74
78
  # We could choose to accept UAB and AB or just AB and etc.
@@ -78,9 +82,9 @@ quote_open = c("„")
78
82
  quote_close = c("“")
79
83
 
80
84
  # Consume LT alphabet with whitespace
81
- company_name = (alpha_with_lt | ws).rep.capture!.map(&:join)
82
- company_info = company_type >> ws.rep0 >> quote_open >> company_name >> quote_close
83
- second_line = ws.rep0 >> company_info >> eol
85
+ company_name = (alpha_with_lt | ws).rep.map(&:join).capture!
86
+ company_info = company_type & ws.rep0 & quote_open & company_name & quote_close
87
+ second_line = ws.rep0 & company_info & eol
84
88
 
85
89
  # Address line
86
90
  # 'char_while' will consume characters while passed predicate is true
@@ -88,35 +92,38 @@ second_line = ws.rep0 >> company_info >> eol
88
92
  # After that result is captured and mapped to hash
89
93
  # Mapping to hash so at the end its easy to tell tuples apart
90
94
  # Also while mapping, doing some cleaning with '.strip'
91
- street_name = char_while(->(char) { !char.match(/\d/) })
92
- .capture!
93
- .map(&:first)
94
- .map { |s| { street: s.strip } }
95
- building = digits.capture!.map(&:first).map { |s| { building: s.strip } }
96
- address_line = ws.rep0 >> street_name >> building >> eol
95
+ street_name = char_while(->(char) { !char.match(/\d/) }).map { |s| { street: s.strip } }.capture!
96
+ building = digits.map { |s| { building: s.strip } }.capture!
97
+ address_line = ws.rep0 & street_name & building & eol
97
98
 
98
99
  # City line
99
- # All digits can be matched here or 'digits.rep(5)' could be used.
100
- # Also joining with map results.
101
- postcode = digits.capture!.map(&:join).map { |s| { postcode: s.strip } }
102
- city = alpha_with_lt.rep.capture!.map(&:join).map { |s| { city: s.strip } }
103
- city_line = ws.rep0 >> postcode >> ws >> city >> eol
104
-
105
- # Full letter parser which is combined from all previous parsers.
106
- # Also, all previous parsers can be ran separately.
107
- letter_parser = name_line >> second_line >> address_line >> city_line
100
+ # All digits can be matched here or 'digits.rep(5)' could be used. Also joining with map.
101
+ postcode = digits.map { |s| { postcode: s.strip } }.capture!
102
+ city = alpha_with_lt.rep.map(&:join).map { |s| { city: s.strip } }.capture!
103
+ city_line = ws.rep0 & postcode & ws & city & eol
104
+
105
+ # Full letter parser which is combined from all previous parsers. All previous parsers can be ran separately.
106
+ letter_parser = name_line & second_line & address_line & city_line
108
107
  result = letter_parser.run(letter)
109
108
 
110
- # List of tuples
111
109
  pp result.captures
112
- # ["Vardeniui", "Pavardeniui", "Lietuvos Paštas", {:street=>"Totorių g."},
113
- # {:building=>"8"}, {:postcode=>"01121"}, {:city=>"Vilnius"}]
114
110
 
115
111
  ```
116
112
  ### Roadmap
117
113
  - Better error handling
118
- - Recursive parser
119
114
  - Benchmarks & parser tests
115
+ - Documentation
116
+ - Performance
117
+
118
+ ### Benchmarks
119
+ `bundle exec ruby benchmarks/json/json.rb`
120
+ ```
121
+ Calculating -------------------------------------
122
+ nested json benchmark
123
+ 0.090 (± 0.0%) i/s - 6.000 in 66.952366s
124
+ ```
125
+ Its very slow, not ready for use yet. API is unstable is as well.
126
+
120
127
 
121
128
  ### Contributing
122
129
  Contributors are welcome. Note: since library is not yet stable, I recommend getting in touch with me before starting to work on something.
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark/ips'
4
+ require 'dolos'
5
+ require 'dolos_common_parsers/common_parsers'
6
+
7
+ include Dolos
8
+ include Dolos::CommonParsers
9
+
10
+ def ws_rep0 = ws.rep0
11
+
12
+ def comma = c(",")
13
+
14
+ def string_literal = (c("\"") >> char_while(->(ch) { ch != "\"" }).opt << c("\""))
15
+
16
+ def boolean = (c("true").map { true } | c("false").map { false })
17
+
18
+ def null = c("null").map { nil }
19
+
20
+ def array = recursive do |arr|
21
+ c("[") >> ws_rep0 >> value.repeat(n_min: 0, separator: (comma << ws_rep0)) << ws_rep0 << c("]")
22
+ end
23
+
24
+ def negative_sign = c("-").opt
25
+
26
+ def decimal_point = c('.').opt
27
+
28
+ def number = (negative_sign & digits & decimal_point & digits.opt).map do |tuple|
29
+ tuple.join.to_f
30
+ end
31
+
32
+ def value = number | object | string_literal | boolean | null | array
33
+
34
+ def key_line = ((string_literal << ws_rep0) << c(":") & ws_rep0 >> value).map do |tuple|
35
+ { tuple[0] => tuple[1] }
36
+ end
37
+
38
+ def key_lines = (key_line << ws_rep0).repeat(n_min: 1, separator: (comma << ws_rep0 << eol.opt)).map do |arr|
39
+ arr.reduce({}) do |acc, hash|
40
+ acc.merge(hash)
41
+ end
42
+ end
43
+
44
+ def object = recursive do |obj|
45
+ c("{") >> ws_rep0 >> key_lines.opt << ws_rep0 << c("}")
46
+ end
47
+
48
+ def json_parser = ws_rep0 >> value
49
+
50
+ json_from_file = File.read('benchmarks/json/random.json')
51
+
52
+ Benchmark.ips do |x|
53
+ x.time = 60
54
+ x.warmup = 15
55
+
56
+ x.report('nested json benchmark') do
57
+ json_parser.run(json_from_file)
58
+ end
59
+ x.compare!
60
+ end