parameter_substitution 0.3.0.pre.1 → 1.1.0.pre.1
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.
- checksums.yaml +5 -5
- data/lib/parameter_substitution.rb +1 -2
- data/lib/parameter_substitution/configuration.rb +39 -0
- data/lib/parameter_substitution/context.rb +74 -0
- data/lib/parameter_substitution/encoder.rb +86 -0
- data/lib/parameter_substitution/expression.rb +146 -0
- data/lib/parameter_substitution/formatters/add_prefix.rb +19 -0
- data/lib/parameter_substitution/formatters/base.rb +46 -0
- data/lib/parameter_substitution/formatters/blank_if_nil.rb +11 -0
- data/lib/parameter_substitution/formatters/cgi_unescape.rb +11 -0
- data/lib/parameter_substitution/formatters/compare_string.rb +21 -0
- data/lib/parameter_substitution/formatters/date_time_custom.rb +22 -0
- data/lib/parameter_substitution/formatters/date_time_format.rb +53 -0
- data/lib/parameter_substitution/formatters/date_time_iso8601.rb +11 -0
- data/lib/parameter_substitution/formatters/date_time_iso8601_zulu.rb +11 -0
- data/lib/parameter_substitution/formatters/date_time_strftime.rb +19 -0
- data/lib/parameter_substitution/formatters/date_time_unix_timestamp.rb +11 -0
- data/lib/parameter_substitution/formatters/date_time_us_all_slashes.rb +11 -0
- data/lib/parameter_substitution/formatters/date_time_us_normal.rb +11 -0
- data/lib/parameter_substitution/formatters/date_time_us_seconds.rb +11 -0
- data/lib/parameter_substitution/formatters/date_time_us_short_am_pm.rb +11 -0
- data/lib/parameter_substitution/formatters/date_time_us_short_year.rb +11 -0
- data/lib/parameter_substitution/formatters/date_time_utc_year_first_dashes_seconds.rb +11 -0
- data/lib/parameter_substitution/formatters/date_us_dashes.rb +11 -0
- data/lib/parameter_substitution/formatters/date_us_normal.rb +11 -0
- data/lib/parameter_substitution/formatters/date_year_first_dashes.rb +11 -0
- data/lib/parameter_substitution/formatters/downcase.rb +11 -0
- data/lib/parameter_substitution/formatters/duration_as_seconds.rb +11 -0
- data/lib/parameter_substitution/formatters/duration_as_time.rb +11 -0
- data/lib/parameter_substitution/formatters/duration_grouped_by_description.rb +23 -0
- data/lib/parameter_substitution/formatters/greater_than_value.rb +21 -0
- data/lib/parameter_substitution/formatters/if_nil.rb +19 -0
- data/lib/parameter_substitution/formatters/if_truthy.rb +36 -0
- data/lib/parameter_substitution/formatters/in_timezone.rb +23 -0
- data/lib/parameter_substitution/formatters/json_parse.rb +26 -0
- data/lib/parameter_substitution/formatters/left.rb +19 -0
- data/lib/parameter_substitution/formatters/lookup.rb +19 -0
- data/lib/parameter_substitution/formatters/lower.rb +11 -0
- data/lib/parameter_substitution/formatters/manager.rb +35 -0
- data/lib/parameter_substitution/formatters/md5.rb +11 -0
- data/lib/parameter_substitution/formatters/mid.rb +20 -0
- data/lib/parameter_substitution/formatters/parse_time.rb +23 -0
- data/lib/parameter_substitution/formatters/right.rb +23 -0
- data/lib/parameter_substitution/formatters/sha256.rb +11 -0
- data/lib/parameter_substitution/formatters/split_after_colon.rb +11 -0
- data/lib/parameter_substitution/formatters/split_and_find.rb +20 -0
- data/lib/parameter_substitution/formatters/split_before_colon.rb +11 -0
- data/lib/parameter_substitution/formatters/time_with_seconds.rb +11 -0
- data/lib/parameter_substitution/formatters/trim.rb +11 -0
- data/lib/parameter_substitution/formatters/upper.rb +11 -0
- data/lib/parameter_substitution/method_call_expression.rb +58 -0
- data/lib/parameter_substitution/parse_error.rb +6 -0
- data/lib/parameter_substitution/parser.rb +109 -0
- data/lib/parameter_substitution/substitution_expression.rb +79 -0
- data/lib/parameter_substitution/text_expression.rb +52 -0
- data/lib/parameter_substitution/transform.rb +99 -0
- data/lib/parameter_substitution/version.rb +5 -0
- metadata +117 -10
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::JsonParse < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Attempts to parse strings as JSON. If valid, passes along the parsed object, if not valid json, or not a string, passes the json encoded value."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.has_parameters?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.encoding
|
13
|
+
:json
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.format(value)
|
17
|
+
if value.is_a?(String)
|
18
|
+
JSON.parse(value)
|
19
|
+
value
|
20
|
+
else
|
21
|
+
value.to_json
|
22
|
+
end
|
23
|
+
rescue JSON::ParserError
|
24
|
+
value.to_json
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Left < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Takes a single n argument. Returns the left most n characters from the input."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.has_parameters?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(character_count)
|
13
|
+
@character_count = character_count
|
14
|
+
end
|
15
|
+
|
16
|
+
def format(value)
|
17
|
+
value.to_s[0, @character_count]
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Lookup < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"This takes a table as a constructor parameter and performs a lookup from the value. If the value exists as a key in the lookup table, the key's value is returned."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.has_parameters?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(lookup_table)
|
13
|
+
@lookup_table = lookup_table
|
14
|
+
end
|
15
|
+
|
16
|
+
def format(value)
|
17
|
+
@lookup_table[value.to_s]
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Lower < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Converts to string and returns all characters lowercased, preserves nil."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format(value)
|
9
|
+
value&.to_s&.downcase
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution
|
4
|
+
module Formatters
|
5
|
+
class Manager
|
6
|
+
class << self
|
7
|
+
def find(key)
|
8
|
+
all_formats[key.to_s]
|
9
|
+
end
|
10
|
+
|
11
|
+
def all_formats
|
12
|
+
default_formats.merge(custom_formatters_if_any)
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_formats
|
16
|
+
@default_formats ||= formatter_class_hash(__FILE__, ["ParameterSubstitution", "Formatters"])
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def formatter_class_hash(manager_file, module_array)
|
22
|
+
Hash[Dir[Pathname.new(manager_file).dirname + '*.rb'].map do |filename|
|
23
|
+
class_key = File.basename(filename).chomp(".rb")
|
24
|
+
class_name = (module_array + [class_key.camelize.to_s]).join('::').constantize
|
25
|
+
[class_key, class_name]
|
26
|
+
end].except("manager")
|
27
|
+
end
|
28
|
+
|
29
|
+
def custom_formatters_if_any
|
30
|
+
ParameterSubstitution.config&.custom_formatters || {}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Md5 < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Generates an md5 hash of the value."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format(value)
|
9
|
+
Digest::MD5.hexdigest(value.to_s)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Mid < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Takes starting_position and character_count as arguments. Returns the character_count characters starting from starting_position from the input."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.has_parameters?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(starting_position, character_count)
|
13
|
+
@starting_position = starting_position
|
14
|
+
@character_count = character_count
|
15
|
+
end
|
16
|
+
|
17
|
+
def format(value)
|
18
|
+
value.to_s[@starting_position, @character_count]
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::ParseTime < ParameterSubstitution::Formatters::DateTimeFormat
|
4
|
+
def self.description
|
5
|
+
"Takes format_string as a parameter and uses format_string to parse the input as a time. Does not change the input if the value is not a time."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.has_parameters?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(format_string)
|
13
|
+
@format_string = format_string
|
14
|
+
end
|
15
|
+
|
16
|
+
def format(value)
|
17
|
+
value && Time.strptime(value.to_s, @format_string).strftime('%Y-%m-%d %H:%M:%S')
|
18
|
+
rescue ArgumentError => ex
|
19
|
+
# strptime raises argument error if either argument is wrong.
|
20
|
+
ex.message =~ /invalid .*strptime format/ or raise
|
21
|
+
value
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Right < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Takes a single n argument. Returns the right most n characters from the input."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.has_parameters?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(character_count)
|
13
|
+
@character_count = character_count
|
14
|
+
end
|
15
|
+
|
16
|
+
def format(value)
|
17
|
+
if (as_string = value.to_s).size > @character_count
|
18
|
+
as_string[-@character_count, @character_count]
|
19
|
+
else
|
20
|
+
as_string
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Sha256 < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Generates a sha256 hash of the value."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format(value)
|
9
|
+
Digest::SHA256.hexdigest(value.to_s)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::SplitAfterColon < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Returns the portion of a string after the first colon, or nil if there is no colon."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format(value)
|
9
|
+
value && value.to_s.split(':', 2)[1]&.lstrip
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::SplitAndFind < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Takes delimiter and index as arguments. Splits the input on delimiters and returns the indexed element. Preserves nil."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.has_parameters?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(delimiter, index)
|
13
|
+
@delimiter = delimiter
|
14
|
+
@index = index
|
15
|
+
end
|
16
|
+
|
17
|
+
def format(value)
|
18
|
+
value && value.to_s.split(@delimiter)[@index]
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::SplitBeforeColon < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Returns the portion of a string before the first colon, or the full string if there is no colon."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format(value)
|
9
|
+
value && value.to_s.split(':')[0]
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::TimeWithSeconds < ParameterSubstitution::Formatters::DateTimeFormat
|
4
|
+
def self.description
|
5
|
+
"hh:mm:ss"
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format(value)
|
9
|
+
parse_to_time(value)&.strftime("%H:%M:%S").to_s
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Trim < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Returns the input as a string with leading and trailing whitespace removed."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format(value)
|
9
|
+
value&.to_s&.strip
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution::Formatters::Upper < ParameterSubstitution::Formatters::Base
|
4
|
+
def self.description
|
5
|
+
"Converts to string and returns all characters uppercased, preserves nil."
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format(value)
|
9
|
+
value&.to_s&.upcase
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParameterSubstitution
|
4
|
+
class MethodCallExpression
|
5
|
+
attr_reader :name, :arguments
|
6
|
+
|
7
|
+
def initialize(name, arguments)
|
8
|
+
@name = name
|
9
|
+
@arguments = arguments || []
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate
|
13
|
+
if format_class
|
14
|
+
expected_arguments = format_class&.has_parameters? ? format_class.instance_method(:initialize).arity : 0
|
15
|
+
if @arguments.size != expected_arguments
|
16
|
+
raise ParameterSubstitution::ParseError, "Wrong number of arguments for '#{@name}' expected #{expected_arguments}, received #{@arguments.size}"
|
17
|
+
end
|
18
|
+
else
|
19
|
+
raise ParameterSubstitution::ParseError, "Unknown method '#{@name}'"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def call_method(value)
|
24
|
+
column_formatter.format(value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def encoding
|
28
|
+
format_class.encoding
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def column_formatter
|
34
|
+
@column_formatter ||= begin
|
35
|
+
if format_class&.has_parameters?
|
36
|
+
format_class.new(*format_args)
|
37
|
+
else
|
38
|
+
format_class
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def format_class
|
44
|
+
@format_class ||= ParameterSubstitution::Formatters::Manager.find(@name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def format_args
|
48
|
+
@arguments.map do |arg|
|
49
|
+
case arg
|
50
|
+
when ParameterSubstitution::Expression
|
51
|
+
arg.evaluate
|
52
|
+
else
|
53
|
+
arg
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'parslet'
|
4
|
+
#
|
5
|
+
# The parser describes the rules of the grammar, and when executed on a string it will
|
6
|
+
# either fail with an exception or it will return a structure describing what it found.
|
7
|
+
#
|
8
|
+
# See the parslet documentation for more detail.
|
9
|
+
#
|
10
|
+
|
11
|
+
class ParameterSubstitution
|
12
|
+
class Parser < Parslet::Parser
|
13
|
+
def initialize(parameter_start: "<", parameter_end: ">", allow_unmatched_parameter_end: false)
|
14
|
+
@parameter_start = parameter_start
|
15
|
+
@parameter_end = parameter_end
|
16
|
+
@allow_unmatched_parameter_end = allow_unmatched_parameter_end
|
17
|
+
super()
|
18
|
+
end
|
19
|
+
|
20
|
+
root :text_with_substitution_parameters
|
21
|
+
|
22
|
+
rule(:double_quote) { str("\"") }
|
23
|
+
rule(:single_quote) { str("\'") }
|
24
|
+
rule(:escape) { str("\\") }
|
25
|
+
rule(:dot) { str(".") }
|
26
|
+
rule(:open_param) { str(@parameter_start) }
|
27
|
+
rule(:close_param) { str(@parameter_end) }
|
28
|
+
rule(:digit) { match["0-9"] }
|
29
|
+
rule(:parameter_start) { str("(") }
|
30
|
+
rule(:parameter_end) { str(")") }
|
31
|
+
rule(:space) { str(" ") }
|
32
|
+
rule(:space?) { space.repeat }
|
33
|
+
rule(:comma) { space? >> str(",") >> space? }
|
34
|
+
|
35
|
+
rule :double_quoted_string_arg do
|
36
|
+
double_quote >> (escape >> any | double_quote.absent? >> any).repeat.as(:string_arg) >> double_quote
|
37
|
+
end
|
38
|
+
|
39
|
+
rule :single_quoted_string_arg do
|
40
|
+
single_quote >> (escape >> any | single_quote.absent? >> any).repeat.as(:string_arg) >> single_quote
|
41
|
+
end
|
42
|
+
|
43
|
+
rule :string_arg do
|
44
|
+
double_quoted_string_arg | single_quoted_string_arg
|
45
|
+
end
|
46
|
+
|
47
|
+
rule :float_arg do
|
48
|
+
(digit.repeat(1) >> dot >> digit.repeat(1)).as(:float_arg)
|
49
|
+
end
|
50
|
+
|
51
|
+
rule :int_arg do
|
52
|
+
digit.repeat(1).as(:int_arg)
|
53
|
+
end
|
54
|
+
|
55
|
+
rule :nil_arg do
|
56
|
+
str('nil').as(:nil_arg)
|
57
|
+
end
|
58
|
+
|
59
|
+
rule :substitution_parameter_arg do
|
60
|
+
open_param >> parameter.repeat.as(:raw_expression) >> close_param
|
61
|
+
end
|
62
|
+
|
63
|
+
rule :arg do
|
64
|
+
float_arg | string_arg | int_arg | nil_arg | substitution_parameter_arg
|
65
|
+
end
|
66
|
+
|
67
|
+
rule :argument_list do
|
68
|
+
parameter_start >> space? >> (arg >> (comma >> arg).repeat).repeat(0, 1).as(:arg_list) >> space? >> parameter_end
|
69
|
+
end
|
70
|
+
|
71
|
+
rule :method_name do
|
72
|
+
(parameter_start.absent? >> close_param.absent? >> dot.absent? >> any).repeat(1).as(:method_call)
|
73
|
+
end
|
74
|
+
|
75
|
+
rule :method_call do
|
76
|
+
method_name >> argument_list.maybe
|
77
|
+
end
|
78
|
+
|
79
|
+
rule :method_call_list do
|
80
|
+
(dot >> method_call).repeat(0)
|
81
|
+
end
|
82
|
+
|
83
|
+
rule :parameter_name do
|
84
|
+
((escape >> any) | (open_param.absent? >> close_param.absent? >> dot.absent? >> any)).repeat(1)
|
85
|
+
end
|
86
|
+
|
87
|
+
rule :parameter do
|
88
|
+
parameter_name.as(:parameter_name) >> method_call_list.as(:method_calls)
|
89
|
+
end
|
90
|
+
|
91
|
+
rule :substitution_parameter_with_brackets do
|
92
|
+
open_param >> parameter >> close_param
|
93
|
+
end
|
94
|
+
|
95
|
+
rule :text do
|
96
|
+
text_char =
|
97
|
+
if @allow_unmatched_parameter_end
|
98
|
+
(open_param.absent? >> any)
|
99
|
+
else
|
100
|
+
(open_param.absent? >> close_param.absent? >> any)
|
101
|
+
end
|
102
|
+
text_char.repeat(1).as(:text)
|
103
|
+
end
|
104
|
+
|
105
|
+
rule :text_with_substitution_parameters do
|
106
|
+
(text | substitution_parameter_with_brackets).repeat.as(:expression)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|