curly_bracket_parser 0.0.1 → 0.9.9

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: 437e9b2cda38fa373852f4b2f67a35428f99d5c78928820b539ae8c5ecf77d09
4
- data.tar.gz: b11dd97f668eff6128b5ae0a9846189c7a8e6291953e7a475080fe705247e9f3
3
+ metadata.gz: c287b3fc82c91116b7c0ca2f982b81bac5c37e4ca286cd1ea8606de75e0c214f
4
+ data.tar.gz: 04f59765b1f59ea540d1e152bbc88c0294ca5adc681f30bf1efed3a117cb3afa
5
5
  SHA512:
6
- metadata.gz: d8286bc6b15346a2babed4de6894be8fadad6c84c9d51ad759fdae906ecec41fdc50d28cf294fb3f8f1b67b6745bf6206e95d337f743ed82fc488cd77b4c6bea
7
- data.tar.gz: 3aab318c0069bf40f73443eefb0245e53c35bbddfb6373883e921ae32e3ebd1b26050319ab24e6336baf98283023ee9232a36dd2655745ee3b018170836a490d
6
+ metadata.gz: 685345c3a8551e0749742550f2dae6784501fefa07318b8e76b2b30fd743c96d1571d2550bee0731a1c1609d82055ec39ff943a6aebf3c39db435d4686d8e01c
7
+ data.tar.gz: a19c4ffb4fe23ce4945023604aeb34ee28a88bd6f89cf2df08f5eab63151fbb0f1ec6b7ec337f6cc8c0b8d2b57c8dacbfec19cbec7b70b22d68cc8b4caf965c6
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # curly_bracket_parser
2
2
 
3
- Simple parser to replace curly brackets {{like_this}} inside strings like URLs, Texts or even files easily.
3
+ Ruby gem providing a simple parser to replace curly brackets `{{like_this}}` inside strings like URLs, texts or even files easily.
4
4
 
5
- alpha version ... to be done ...
5
+ Additional support for build-in filters and custom filters make them more powerful. `{{example|my_filter}}`
6
6
 
7
+ Using [LuckyCase](https://github.com/magynhard/lucky_case), all its case formats are supported as filter by default.
7
8
 
8
9
 
9
10
 
@@ -12,7 +13,7 @@ alpha version ... to be done ...
12
13
  # Contents
13
14
 
14
15
  * [Installation](#installation)
15
- * [Usage](#usage)
16
+ * [Usage examples](#usage)
16
17
  * [Documentation](#documentation)
17
18
  * [Contributing](#contributing)
18
19
 
@@ -36,23 +37,13 @@ Or install it yourself as:
36
37
 
37
38
  $ gem install curly_bracket_parser
38
39
 
39
- ## Common information
40
-
41
- TODO
42
-
43
-
44
-
45
-
46
-
47
40
 
48
41
  <a name="usage"></a>
49
- ## Usage
42
+ ## Usage examples
50
43
 
51
- TODO
44
+ You can either parse variables inside strings or even directly in files.
52
45
 
53
- ### Examples
54
-
55
- #### Basic
46
+ ### Basic
56
47
 
57
48
  ```ruby
58
49
  url = "https://my-domain.com/items/{{item_id}}"
@@ -60,7 +51,7 @@ TODO
60
51
  # => "https://my-domain.com/items/123"
61
52
  ```
62
53
 
63
- #### Filters
54
+ ### Filters
64
55
 
65
56
  ```ruby
66
57
  url = "https://my-domain.com/catalog/{{item_name|snake_case}}"
@@ -68,9 +59,51 @@ TODO
68
59
  # => "https://my-domain.com/catalog/mega_super_item"
69
60
  ```
70
61
 
71
- #### Globals
62
+ For a list of built-in filters visit [LuckyCase](https://github.com/magynhard/lucky_case).
63
+
64
+ #### Define your custom filter
65
+
66
+ ```ruby
67
+ CurlyBracketParser.register_filter('7times') do |string|
68
+ string.to_s * 7
69
+ end
70
+
71
+ text = "Paul went out and screamed: A{{scream|7times}}h"
72
+ final_text = CurlyBracketParser.parse text, scream: 'a'
73
+ # => "Paul went out and screamed: Aaaaaaaah"
74
+ ```
75
+
76
+ ### Files
77
+
78
+ <ins>test.html</ins>
79
+ ```html
80
+ <h1>{{title|sentence_case}}</h1>
81
+ ```
82
+
83
+ ```ruby
84
+ parsed_file = CurlyBracketParser.parse_file './test.html', title: 'WelcomeAtHome'
85
+ # => "<h1>Welcome at home</h1>"
86
+ ```
87
+
88
+ Use `#parse_file!` instead to write the parsed string directly into the file!
89
+
90
+ ### Default variables
91
+
92
+ You can define default variables, which will be replaced automatically without passing them by parameters, but can be overwritten with parameters.
72
93
 
73
- TODO
94
+ Because of providing blocks, your variables can dynamically depend on other states (e.g. current date).
95
+
96
+ ```ruby
97
+ CurlyBracketParser.register_default_var('version') do
98
+ '1.0.2'
99
+ end
100
+
101
+ text = "You are running version {{version}}"
102
+ CurlyBracketParser.parse text
103
+ # => "You are running version 1.0.2"
104
+ CurlyBracketParser.parse text, version: '0.7.0'
105
+ # => "You are running version 0.7.0"
106
+ ```
74
107
 
75
108
 
76
109
 
@@ -1,7 +1,11 @@
1
1
  require 'lucky_case'
2
2
 
3
3
  require 'curly_bracket_parser/version'
4
+ require_relative 'custom_errors/filter_already_registered_error'
5
+ require_relative 'custom_errors/invalid_filter_error'
6
+ require_relative 'custom_errors/invalid_variable_error'
4
7
  require_relative 'custom_errors/unresolved_variables_error'
8
+ require_relative 'custom_errors/variable_already_registered_error'
5
9
 
6
10
  #
7
11
  # CurlyBracketParser
@@ -17,25 +21,37 @@ module CurlyBracketParser
17
21
  VARIABLE_DECODER_REGEX = /{{([^{}\|]+)\|?([^{}\|]*)}}/
18
22
  VARIABLE_REGEX = /{{[^{}]+}}/
19
23
 
20
- VALID_FILTERS = [
21
- LuckyCase::CASES.keys.map(&:to_s)
24
+ VALID_DEFAULT_FILTERS = [
25
+ LuckyCase::CASES.keys.map(&:to_s)
22
26
  ].flatten
23
27
 
24
28
  #----------------------------------------------------------------------------------------------------
25
29
 
30
+ # Parse given string and replace the included variables by the given variables
31
+ #
26
32
  # @param [String] string to parse
27
33
  # @param [Hash<Symbol => String>] variables <key: 'value'>
28
34
  # @param [Symbol] unresolved_vars :raise, :keep, :replace => define how to act when unresolved variables within the string are found.
29
- # @param [String] replace_pattern pattern used when param unresolved_vars is set to :replace. You can include the var name \\1 and filter \\1. Empty string to remove unresolved variables.
35
+ # @param [String] replace_pattern pattern used when param unresolved_vars is set to :replace. You can include the var name \\1 and filter \\2. Empty string to remove unresolved variables.
30
36
  # @return [String, UnresolvedVariablesError] parsed string
31
37
  def self.parse(string, variables, unresolved_vars: :raise, replace_pattern: "##\\1##")
38
+ variables ||= {}
32
39
  result_string = string.clone
33
40
  if CurlyBracketParser.any_variable_included? string
34
41
  loop do
35
42
  variables(string).each do |string_var|
36
- name, filter = decode_variable(string_var)
43
+ dec = decode_variable(string_var)
44
+ name = dec[:name]
45
+ filter = dec[:filter]
37
46
  if variables[name.to_sym]
38
- value = process_filter(variables[name.to_sym], filter)
47
+ value = if filter
48
+ process_filter(filter, variables[name.to_sym])
49
+ else
50
+ variables[name.to_sym]
51
+ end
52
+ result_string.gsub!(string_var, value)
53
+ elsif registered_default_var?(name.to_s)
54
+ value = process_default_var(name)
39
55
  result_string.gsub!(string_var, value)
40
56
  end
41
57
  end
@@ -56,45 +72,178 @@ module CurlyBracketParser
56
72
 
57
73
  #----------------------------------------------------------------------------------------------------
58
74
 
59
- def self.parse_file(path, variables, options = {})
60
- raise "NOT IMPLEMENTED YET!"
75
+ # Parse the content of the file of the given path with #parse and return it.
76
+ # The original file keeps unmodified.
77
+ #
78
+ # @param [String] string to parse
79
+ # @param [Hash<Symbol => String>] variables <key: 'value'>
80
+ # @param [Symbol] unresolved_vars :raise, :keep, :replace => define how to act when unresolved variables within the string are found.
81
+ # @param [String] replace_pattern pattern used when param unresolved_vars is set to :replace. You can include the var name \\1 and filter \\1. Empty string to remove unresolved variables.
82
+ # @return [String, UnresolvedVariablesError] parsed string
83
+ def self.parse_file(path, variables, unresolved_vars: :raise, replace_pattern: "##\\1##")
84
+ file_content = File.read path
85
+ parse(file_content, variables, unresolved_vars: unresolved_vars, replace_pattern: replace_pattern)
86
+ end
87
+
88
+ # Parse the content of the file of the given path with #parse and return it.
89
+ # The original file will be overwritten by the parsed content.
90
+ #
91
+ # @param [String] string to parse
92
+ # @param [Hash<Symbol => String>] variables <key: 'value'>
93
+ # @param [Symbol] unresolved_vars :raise, :keep, :replace => define how to act when unresolved variables within the string are found.
94
+ # @param [String] replace_pattern pattern used when param unresolved_vars is set to :replace. You can include the var name \\1 and filter \\1. Empty string to remove unresolved variables.
95
+ # @return [String, UnresolvedVariablesError] parsed string
96
+ def self.parse_file!(path, variables, unresolved_vars: :raise, replace_pattern: "##\\1##")
97
+ parsed_file = parse_file path, variables, unresolved_vars: unresolved_vars, replace_pattern: replace_pattern
98
+ File.write path, parsed_file
99
+ parsed_file
100
+ end
101
+
102
+ #----------------------------------------------------------------------------------------------------
103
+
104
+ # Register your custom filter to the filter list
105
+ #
106
+ # @param [String] filter name of the filter, also used then in your strings, e.g. {{var_name|my_filter_name}}
107
+ # @param [Lambda] function of the filter to run the variable against
108
+ # @raise [FilterAlreadyRegisteredError] if filter does already exist
109
+ # @return [Proc] given block
110
+ def self.register_filter(filter, &block)
111
+ @@registered_filters ||= {}
112
+ filter = filter.to_s
113
+ if valid_filter?(filter)
114
+ raise FilterAlreadyRegisteredError, "The given filter name '#{filter}' is already registered"
115
+ else
116
+ @@registered_filters[filter] = block
117
+ end
61
118
  end
62
119
 
63
- def self.parse_file!(path, variables, options = {})
64
- raise "NOT IMPLEMENTED YET!"
120
+ #----------------------------------------------------------------------------------------------------
121
+
122
+ # Process the given value with the given filter
123
+ #
124
+ # @param [String] filter name of the filter, also used then in your strings, e.g. {{var_name|my_filter_name}}
125
+ # @param [String] value string to apply the specified filter on
126
+ # @return [String] converted string with applied filter
127
+ def self.process_filter(filter, value)
128
+ @@registered_filters ||= {}
129
+ filter = filter.to_s
130
+ if @@registered_filters[filter]
131
+ @@registered_filters[filter].call(value)
132
+ elsif VALID_DEFAULT_FILTERS.include?(filter) && LuckyCase.valid_case_type?(filter)
133
+ LuckyCase.convert_case(value, filter)
134
+ else
135
+ message = "Invalid filter '#{filter}'. Valid filters are: #{self.valid_filters.join(' ')}"
136
+ raise InvalidFilterError, message
137
+ end
65
138
  end
66
139
 
67
140
  #----------------------------------------------------------------------------------------------------
68
141
 
69
- def self.register_filter(name, function)
70
- raise "NOT IMPLEMENTED YET!"
142
+ # Retrieve Array with valid filters
143
+ #
144
+ # @return [Array<String>] of valid filters
145
+ def self.valid_filters
146
+ all_filters = VALID_DEFAULT_FILTERS
147
+ @@registered_filters ||= {}
148
+ all_filters + @@registered_filters.keys.map(&:to_s)
71
149
  end
72
150
 
73
151
  #----------------------------------------------------------------------------------------------------
74
152
 
75
- def self.register_default_variable(name, function)
76
- raise "NOT IMPLEMENTED YET!"
153
+ # Check if a given filter is valid
154
+ #
155
+ # @param [String] name
156
+ # @return [Boolean] true if filter exists, otherwise false
157
+ def self.valid_filter?(name)
158
+ self.valid_filters.include? name
77
159
  end
78
160
 
79
161
  #----------------------------------------------------------------------------------------------------
80
162
 
81
- def self.process_filter(value, filter)
82
- return value unless filter
83
- if VALID_FILTERS.include? filter
84
- if LuckyCase.valid_case_type? filter
85
- return LuckyCase.convert_case(value, filter)
86
- else
87
- raise "FILTER '#{filter}' NOT IMPLEMENTED YET!"
88
- end
163
+ # Register a default variable to be replaced automatically by the given block value in future
164
+ # If the variable exists already, it will raise an VariableAlreadyRegisteredError
165
+ #
166
+ # @param [String] name of the default var
167
+ # @param [Proc] block
168
+ # @raise [VariableAlreadyRegisteredError] if variable is already registered
169
+ # @return [Proc] given block
170
+ def self.register_default_var(name, &block)
171
+ @@registered_default_vars ||= {}
172
+ name = name.to_s
173
+ if registered_default_var?(name)
174
+ raise VariableAlreadyRegisteredError, "The given variable name '#{name}' is already registered. If you want to override that variable explicitly, call #register_default_var! instead!"
175
+ else
176
+ @@registered_default_vars[name] = block
177
+ end
178
+ end
179
+
180
+ #----------------------------------------------------------------------------------------------------
181
+
182
+ # Return the given default variable by returning the result of its block/proc
183
+ #
184
+ # @param [String] name of the variable to return
185
+ # @return [String] value of the variable
186
+ def self.process_default_var(name)
187
+ @@registered_default_vars ||= {}
188
+ name = name.to_s
189
+ if @@registered_default_vars[name]
190
+ @@registered_default_vars[name].call()
191
+ else
192
+ message = "Invalid default variable '#{name}'. Valid registered default variables are: #{self.registered_default_vars.keys.join(' ')}"
193
+ raise InvalidVariableError, message
194
+ end
195
+ end
196
+
197
+ #----------------------------------------------------------------------------------------------------
198
+
199
+ # Register a default variable to be replaced automatically by the given block value in future
200
+ # If the variable exists already, it will be overwritten
201
+ #
202
+ # @param [String] name of the default var
203
+ # @param [Proc] block
204
+ # @raise [VariableAlreadyRegisteredError] if variable is already registered
205
+ # @return [Proc] given block
206
+ def self.register_default_var!(name, &block)
207
+ @@registered_default_vars ||= {}
208
+ name = name.to_s
209
+ @@registered_default_vars[name] = block
210
+ end
211
+
212
+ #----------------------------------------------------------------------------------------------------
213
+
214
+ # Unregister / remove an existing default variable
215
+ #
216
+ # @param [String] name of the variable
217
+ # @return [Boolean] true if variable existed and was unregistered, false if it didn't exist
218
+ def self.unregister_default_var(name)
219
+ @@registered_default_vars ||= {}
220
+ name = name.to_s
221
+ if @@registered_default_vars[name]
222
+ @@registered_default_vars.delete(name)
223
+ true
89
224
  else
90
- raise "Invalid filter '#{filter}'"
225
+ false
91
226
  end
92
227
  end
93
228
 
94
229
  #----------------------------------------------------------------------------------------------------
95
230
 
96
- def self.has_filter?(variable)
97
- decode_variable(variable)[:filter] != nil
231
+ # Return an array of registered default variables
232
+ #
233
+ # @return [Array<String>]
234
+ def self.registered_default_vars
235
+ @@registered_default_vars ||= {}
236
+ @@registered_default_vars.keys.map(&:to_s)
237
+ end
238
+
239
+ #----------------------------------------------------------------------------------------------------
240
+
241
+ # Check if the given variable is a registered default variable
242
+ #
243
+ # @param [String] name of the variable
244
+ # @return [Boolean] true if variable is registered, otherwise false
245
+ def self.registered_default_var?(name)
246
+ self.registered_default_vars.include? name
98
247
  end
99
248
 
100
249
  #----------------------------------------------------------------------------------------------------
@@ -105,26 +254,30 @@ module CurlyBracketParser
105
254
  # '{{var_name|filter_name}}' => { name: 'var_name', filter: 'filter_name' }
106
255
  #
107
256
  # @param [String] variable
108
- # @return [Array(String, String)] name, filter
257
+ # @return [Hash<String => String>] name, filter
109
258
  def self.decode_variable(variable)
110
- var = decoded_variables(variable).first
111
- [var.keys.first, var.values.first]
259
+ decoded_variables(variable).first
112
260
  end
113
261
 
114
262
  #----------------------------------------------------------------------------------------------------
115
263
 
116
- # scans the given url for variables with pattern '{{var}}'
264
+ # Scans the given url for variables with pattern '{{var|optional_filter}}'
265
+ #
266
+ # @example
267
+ # 'The variable {{my_var|my_filter}} is inside this string' => [{ name: "my_var", filter: "my_filter"}]
268
+ #
117
269
  # @param [String] string to scan
118
270
  # @return [Array<Hash<Symbol => String>>] array of variable names and its filters
119
271
  def self.decoded_variables(string)
120
- var_name = 0
121
- var_filter = 1
122
- string.scan(VARIABLE_DECODER_REGEX).map { |e| {"#{e[var_name].strip}": e[var_filter].strip != '' ? e[var_filter].strip : nil } }.flatten
272
+ var_name_index = 0
273
+ var_filter_index = 1
274
+ string.scan(VARIABLE_DECODER_REGEX).map { |e| { name: "#{e[var_name_index].strip}", filter: e[var_filter_index].strip != '' ? e[var_filter_index].strip : nil } }.flatten
123
275
  end
124
276
 
125
277
  #----------------------------------------------------------------------------------------------------
126
278
 
127
- # scans the given url for variables with pattern '{{var}}'
279
+ # Scans the given url for variables with pattern '{{var|optional_filter}}'
280
+ #
128
281
  # @param [String] string to scan
129
282
  # @return [Array<String>] array of variable names and its filters
130
283
  def self.variables(string)
@@ -133,12 +286,21 @@ module CurlyBracketParser
133
286
 
134
287
  #----------------------------------------------------------------------------------------------------
135
288
 
289
+ # Check if any variable is included in the given string
290
+ #
291
+ # @param [String] string name of variable to check for
292
+ # @return [Boolean] true if any variable is included in the given string, otherwise false
136
293
  def self.any_variable_included?(string)
137
294
  string.match(VARIABLE_REGEX) != nil
138
295
  end
139
296
 
140
297
  #----------------------------------------------------------------------------------------------------
141
298
 
299
+ # Check if one of the given variable names is included in the given string
300
+ #
301
+ # @param [Array<String>] variable_names
302
+ # @param [String] string name of variable to check for
303
+ # @return [Boolean] true if one given variable name is included in given the string, otherwise false
142
304
  def self.includes_one_variable_of(variable_names, string)
143
305
  decoded_variables(string).each do |dvar|
144
306
  return true if variable_names.include?(dvar[:name])
@@ -1,3 +1,3 @@
1
1
  module CurlyBracketParser
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.9.9'.freeze
3
3
  end
@@ -0,0 +1,2 @@
1
+ class FilterAlreadyRegisteredError < StandardError
2
+ end
@@ -0,0 +1,2 @@
1
+ class InvalidFilterError < StandardError
2
+ end
@@ -0,0 +1,2 @@
1
+ class InvalidVariableError < StandardError
2
+ end
@@ -0,0 +1,2 @@
1
+ class VariableAlreadyRegisteredError < StandardError
2
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: curly_bracket_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthäus Beyrle
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-17 00:00:00.000000000 Z
11
+ date: 2021-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lucky_case
@@ -85,7 +85,11 @@ files:
85
85
  - curly_bracket_parser.gemspec
86
86
  - lib/curly_bracket_parser.rb
87
87
  - lib/curly_bracket_parser/version.rb
88
+ - lib/custom_errors/filter_already_registered_error.rb
89
+ - lib/custom_errors/invalid_filter_error.rb
90
+ - lib/custom_errors/invalid_variable_error.rb
88
91
  - lib/custom_errors/unresolved_variables_error.rb
92
+ - lib/custom_errors/variable_already_registered_error.rb
89
93
  homepage: https://github.com/magynhard/curly_bracket_parser
90
94
  licenses:
91
95
  - MIT