code-ruby 3.1.2 → 4.0.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.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/code +100 -20
  4. data/lib/code/concerns/shared.rb +335 -15
  5. data/lib/code/format.rb +33 -15
  6. data/lib/code/network.rb +82 -0
  7. data/lib/code/node/call.rb +80 -2
  8. data/lib/code/node/call_argument.rb +14 -0
  9. data/lib/code/node/code.rb +4 -3
  10. data/lib/code/node/function_parameter.rb +7 -4
  11. data/lib/code/node/list.rb +32 -2
  12. data/lib/code/node/square_bracket.rb +4 -2
  13. data/lib/code/object/base_64.rb +132 -6
  14. data/lib/code/object/boolean.rb +56 -0
  15. data/lib/code/object/class.rb +143 -2
  16. data/lib/code/object/code.rb +108 -7
  17. data/lib/code/object/context.rb +59 -1
  18. data/lib/code/object/cryptography.rb +69 -0
  19. data/lib/code/object/date.rb +13800 -462
  20. data/lib/code/object/decimal.rb +1098 -0
  21. data/lib/code/object/dictionary.rb +1861 -11
  22. data/lib/code/object/duration.rb +24 -0
  23. data/lib/code/object/function.rb +289 -27
  24. data/lib/code/object/global.rb +447 -1
  25. data/lib/code/object/html.rb +181 -7
  26. data/lib/code/object/http.rb +253 -17
  27. data/lib/code/object/ics.rb +76 -13
  28. data/lib/code/object/identifier_list.rb +30 -10
  29. data/lib/code/object/integer.rb +1265 -2
  30. data/lib/code/object/json.rb +80 -1
  31. data/lib/code/object/list.rb +3371 -10
  32. data/lib/code/object/nothing.rb +53 -0
  33. data/lib/code/object/number.rb +120 -0
  34. data/lib/code/object/parameter.rb +149 -0
  35. data/lib/code/object/range.rb +530 -14
  36. data/lib/code/object/smtp.rb +103 -12
  37. data/lib/code/object/string.rb +968 -3
  38. data/lib/code/object/super.rb +11 -1
  39. data/lib/code/object/time.rb +13932 -498
  40. data/lib/code/object/url.rb +67 -0
  41. data/lib/code/object.rb +582 -0
  42. data/lib/code/parser.rb +194 -55
  43. data/lib/code-ruby.rb +3 -0
  44. data/lib/code.rb +30 -3
  45. metadata +135 -84
  46. data/.github/dependabot.yml +0 -15
  47. data/.github/workflows/ci.yml +0 -38
  48. data/.gitignore +0 -30
  49. data/.node-version +0 -1
  50. data/.npm-version +0 -1
  51. data/.prettierignore +0 -2
  52. data/.rspec +0 -1
  53. data/.rubocop.yml +0 -140
  54. data/.ruby-version +0 -1
  55. data/.tool-versions +0 -3
  56. data/AGENTS.md +0 -43
  57. data/Gemfile +0 -22
  58. data/Gemfile.lock +0 -292
  59. data/Rakefile +0 -5
  60. data/bin/bundle +0 -123
  61. data/bin/bundle-audit +0 -31
  62. data/bin/bundler-audit +0 -31
  63. data/bin/dorian +0 -31
  64. data/bin/rspec +0 -31
  65. data/bin/rubocop +0 -31
  66. data/bin/test +0 -5
  67. data/code-ruby.gemspec +0 -34
  68. data/docs/precedence.txt +0 -36
  69. data/package-lock.json +0 -14
  70. data/package.json +0 -7
  71. data/spec/bin/code_spec.rb +0 -48
  72. data/spec/code/format_spec.rb +0 -153
  73. data/spec/code/node/call_spec.rb +0 -11
  74. data/spec/code/object/boolean_spec.rb +0 -18
  75. data/spec/code/object/cryptography_spec.rb +0 -25
  76. data/spec/code/object/decimal_spec.rb +0 -50
  77. data/spec/code/object/dictionary_spec.rb +0 -98
  78. data/spec/code/object/function_spec.rb +0 -268
  79. data/spec/code/object/http_spec.rb +0 -33
  80. data/spec/code/object/ics_spec.rb +0 -50
  81. data/spec/code/object/integer_spec.rb +0 -42
  82. data/spec/code/object/list_spec.rb +0 -22
  83. data/spec/code/object/nothing_spec.rb +0 -14
  84. data/spec/code/object/range_spec.rb +0 -23
  85. data/spec/code/object/string_spec.rb +0 -26
  86. data/spec/code/parser/boolean_spec.rb +0 -11
  87. data/spec/code/parser/chained_call_spec.rb +0 -16
  88. data/spec/code/parser/dictionary_spec.rb +0 -18
  89. data/spec/code/parser/function_spec.rb +0 -16
  90. data/spec/code/parser/group_spec.rb +0 -11
  91. data/spec/code/parser/if_modifier_spec.rb +0 -18
  92. data/spec/code/parser/list_spec.rb +0 -17
  93. data/spec/code/parser/number_spec.rb +0 -11
  94. data/spec/code/parser/string_spec.rb +0 -20
  95. data/spec/code/parser_spec.rb +0 -52
  96. data/spec/code/type_spec.rb +0 -21
  97. data/spec/code_spec.rb +0 -717
  98. data/spec/spec_helper.rb +0 -21
  99. data/spec/zeitwerk/loader_spec.rb +0 -7
data/lib/code/format.rb CHANGED
@@ -214,6 +214,7 @@ class Code
214
214
  literal = %("#{content}")
215
215
  return literal if literal.length <= string_inline_limit(indent)
216
216
  return literal unless allow_split
217
+ return literal if content.include?("\\")
217
218
 
218
219
  split_string_literal(components, indent: indent)
219
220
  end
@@ -331,7 +332,7 @@ class Code
331
332
  def format_dictionary_statement_code(statement_code)
332
333
  key =
333
334
  format_dictionary_statement_key(statement_code[:statement]) ||
334
- format_nested_statement(statement_code[:statement], indent: 0)
335
+ format_nested_statement(statement_code[:statement], indent: 0)
335
336
  return key unless statement_code.key?(:code)
336
337
 
337
338
  value = format_code_inline(statement_code[:code], indent: 0)
@@ -380,6 +381,14 @@ class Code
380
381
  return format_code_inline(Array(argument), indent: 0)
381
382
  end
382
383
 
384
+ if argument.key?(:operator)
385
+ return argument[:operator].to_s unless argument.key?(:value)
386
+
387
+ value = format_code_inline(argument[:value], indent: 0)
388
+
389
+ return "#{argument[:operator]}#{value}"
390
+ end
391
+
383
392
  value = format_code_inline(argument[:value], indent: 0)
384
393
  return value unless argument.key?(:name)
385
394
 
@@ -423,6 +432,8 @@ class Code
423
432
  parameter[:spread]
424
433
  elsif parameter.key?(:block)
425
434
  parameter[:block]
435
+ elsif parameter.key?(:blocks)
436
+ parameter[:blocks]
426
437
  else
427
438
  ""
428
439
  end
@@ -463,14 +474,17 @@ class Code
463
474
  first_line, *rest = right.lines(chomp: true)
464
475
  if multiline_operand_statement?(other[:statement]) ||
465
476
  !BOOLEAN_WORD_OPERATORS.include?(operator)
466
- ["#{expression} #{operator} #{first_line.lstrip}", *rest].join("\n")
477
+ ["#{expression} #{operator} #{first_line.lstrip}", *rest].join(
478
+ "\n"
479
+ )
467
480
  else
468
481
  [
469
482
  "#{expression}\n#{INDENT * (indent + 1)}#{operator} #{first_line.lstrip}",
470
483
  *rest
471
484
  ].join("\n")
472
485
  end
473
- elsif expression.include?("\n") || candidate.length > MAX_LINE_LENGTH
486
+ elsif expression.include?("\n") ||
487
+ candidate.length > MAX_LINE_LENGTH
474
488
  right_lines =
475
489
  if right.include?("\n")
476
490
  right.lines(chomp: true).map(&:lstrip)
@@ -507,10 +521,9 @@ class Code
507
521
  return false if expression.lstrip.start_with?("(")
508
522
 
509
523
  continuation_lines =
510
- expression
511
- .lines(chomp: true)[1..]
512
- .to_a
513
- .reject { |line| line.strip.empty? || line.strip.match?(/\A[\])}]+\z/) }
524
+ expression.lines(chomp: true)[1..].to_a.reject do |line|
525
+ line.strip.empty? || line.strip.match?(/\A[\])}]+\z/)
526
+ end
514
527
 
515
528
  return false if continuation_lines.empty?
516
529
 
@@ -564,10 +577,7 @@ class Code
564
577
  first_line = first_line.lstrip
565
578
  return "#{left} #{operator} #{first_line}" if rest.empty?
566
579
 
567
- return [
568
- "#{left} #{operator} #{first_line}",
569
- *rest
570
- ].join("\n")
580
+ return ["#{left} #{operator} #{first_line}", *rest].join("\n")
571
581
  end
572
582
 
573
583
  "#{left} #{operator} #{right}"
@@ -580,7 +590,9 @@ class Code
580
590
  if nested_operator == "="
581
591
  left = format_nested_statement(nested[:left], indent: indent)
582
592
  right = format_nested_statement(nested[:right], indent: indent)
583
- return "#{left} #{nested_operator} #{group_multiline_expression(right, indent: indent)}"
593
+ return(
594
+ "#{left} #{nested_operator} #{group_multiline_expression(right, indent: indent)}"
595
+ )
584
596
  end
585
597
  end
586
598
 
@@ -710,7 +722,8 @@ class Code
710
722
  Array(while_statement[:parameters]).map do |parameter|
711
723
  format_parameter(parameter, indent: indent)
712
724
  end
713
- header = parameters.empty? ? "loop {" : "loop { |#{parameters.join(", ")}|"
725
+ header =
726
+ parameters.empty? ? "loop {" : "loop { |#{parameters.join(", ")}|"
714
727
 
715
728
  return "#{INDENT * indent}#{header}\n#{body}\n#{INDENT * indent}}"
716
729
  end
@@ -743,7 +756,9 @@ class Code
743
756
  others = Array(operation[:others])
744
757
 
745
758
  return false if others.empty?
746
- return false unless others.all? { |other| compact_operator?(other[:operator]) }
759
+ unless others.all? { |other| compact_operator?(other[:operator]) }
760
+ return false
761
+ end
747
762
 
748
763
  return multiline_operand_statement?(operation[:first])
749
764
  end
@@ -771,7 +786,10 @@ class Code
771
786
 
772
787
  def indent_lines(value, indent)
773
788
  prefix = INDENT * indent
774
- value.split("\n").map { |line| line.empty? ? "" : "#{prefix}#{line}" }.join("\n")
789
+ value
790
+ .split("\n")
791
+ .map { |line| line.empty? ? "" : "#{prefix}#{line}" }
792
+ .join("\n")
775
793
  end
776
794
 
777
795
  def statement_separator(inline:, indent: nil)
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Code
4
+ module Network
5
+ BLOCKED_HOSTS = %w[localhost localhost.localdomain].freeze
6
+ BLOCKED_HOST_SUFFIXES = %w[.local .localhost].freeze
7
+ BLOCKED_IP_RANGES =
8
+ %w[
9
+ 0.0.0.0/8
10
+ 10.0.0.0/8
11
+ 100.64.0.0/10
12
+ 127.0.0.0/8
13
+ 169.254.0.0/16
14
+ 172.16.0.0/12
15
+ 192.0.0.0/24
16
+ 192.168.0.0/16
17
+ 224.0.0.0/4
18
+ 240.0.0.0/4
19
+ ::/128
20
+ ::1/128
21
+ 64:ff9b::/96
22
+ 64:ff9b:1::/48
23
+ 2002::/16
24
+ fc00::/7
25
+ fe80::/10
26
+ ff00::/8
27
+ ].map { |range| IPAddr.new(range) }.freeze
28
+
29
+ def self.validate_public_uri!(uri, service:)
30
+ unless %w[http https].include?(uri.scheme)
31
+ raise Error, "#{service}: unsupported url scheme"
32
+ end
33
+
34
+ validate_public_host!(uri.hostname, service: service).first
35
+ end
36
+
37
+ def self.validate_public_host!(host, service:)
38
+ normalized_host = normalize_host(host)
39
+
40
+ if blocked_hostname?(normalized_host)
41
+ raise Error, "#{service}: local network requests are not allowed"
42
+ end
43
+
44
+ addresses = resolved_addresses(normalized_host)
45
+ raise Error, "#{service}: could not resolve host" if addresses.empty?
46
+
47
+ if addresses.any? { |address| blocked_address?(address) }
48
+ raise Error, "#{service}: local network requests are not allowed"
49
+ end
50
+
51
+ addresses
52
+ rescue Resolv::ResolvError, ArgumentError
53
+ raise Error, "#{service}: could not resolve host"
54
+ end
55
+
56
+ def self.blocked_address?(address)
57
+ ip = IPAddr.new(address)
58
+ ip = ip.native if ip.respond_to?(:ipv4_mapped?) && ip.ipv4_mapped?
59
+ ip = ip.native if ip.respond_to?(:ipv4_compat?) && ip.ipv4_compat?
60
+
61
+ BLOCKED_IP_RANGES.any? { |range| range.include?(ip) }
62
+ end
63
+
64
+ def self.resolved_addresses(host)
65
+ [IPAddr.new(host).to_s]
66
+ rescue ArgumentError
67
+ Resolv.getaddresses(host)
68
+ end
69
+
70
+ def self.normalize_host(host)
71
+ normalized_host = host.to_s.downcase.delete_suffix(".")
72
+ raise Error, "network: invalid host" if normalized_host.blank?
73
+
74
+ normalized_host
75
+ end
76
+
77
+ def self.blocked_hostname?(host)
78
+ BLOCKED_HOSTS.include?(host) ||
79
+ BLOCKED_HOST_SUFFIXES.any? { |suffix| host.end_with?(suffix) }
80
+ end
81
+ end
82
+ end
@@ -36,7 +36,9 @@ class Code
36
36
  arguments = []
37
37
 
38
38
  (@arguments || []).each do |argument|
39
- if argument.keyword?
39
+ if argument.expansion?
40
+ append_expanded_argument(arguments, argument, **args)
41
+ elsif argument.keyword?
40
42
  if arguments.last.is_a?(Object::Dictionary)
41
43
  arguments.last.code_merge!(argument.evaluate(**args))
42
44
  else
@@ -51,7 +53,18 @@ class Code
51
53
 
52
54
  name = Object::String.new(@name)
53
55
 
54
- args.fetch(:object).call(
56
+ object = args.fetch(:object)
57
+ dynamic_result =
58
+ object.code_dynamic_call(
59
+ name,
60
+ operator: name,
61
+ arguments: Object::List.new(arguments),
62
+ explicit_arguments: @explicit_arguments,
63
+ **args
64
+ )
65
+ return dynamic_result if dynamic_result
66
+
67
+ object.call(
55
68
  operator: name,
56
69
  arguments: Object::List.new(arguments),
57
70
  explicit_arguments: @explicit_arguments,
@@ -62,6 +75,71 @@ class Code
62
75
  def resolve(**_args)
63
76
  Object::String.new(@name)
64
77
  end
78
+
79
+ private
80
+
81
+ def append_expanded_argument(arguments, argument, **args)
82
+ value =
83
+ if argument.value?
84
+ argument.evaluate(**args)
85
+ else
86
+ default_forwarded_argument(argument.operator, args.fetch(:context))
87
+ end
88
+ return if value.nil?
89
+
90
+ case argument.operator
91
+ when "*", "&&"
92
+ value.to_code.code_to_list.raw.each { |item| arguments << item }
93
+ when "**"
94
+ dictionary = value.to_code.code_to_dictionary
95
+ if arguments.last.is_a?(Object::Dictionary)
96
+ arguments.last.code_merge!(dictionary)
97
+ else
98
+ arguments << dictionary
99
+ end
100
+ when "&"
101
+ code_value = value.to_code
102
+ arguments << if code_value.is_a?(Object::Function) ||
103
+ code_value.nothing?
104
+ code_value
105
+ else
106
+ code_value.call(operator: "&", **args)
107
+ end
108
+ when "..."
109
+ expanded_arguments(value, args.fetch(:context)).each do |item|
110
+ arguments << item
111
+ end
112
+ end
113
+ end
114
+
115
+ def default_forwarded_argument(operator, context)
116
+ case operator
117
+ when "*"
118
+ context_fetch(context, "arguments") || Object::List.new
119
+ when "**"
120
+ context_fetch(context, "keyword_arguments")
121
+ when "&"
122
+ context_fetch(context, "block")
123
+ when "&&"
124
+ context_fetch(context, "blocks") || Object::List.new
125
+ when "..."
126
+ context_fetch(context, "rest") || Object::List.new
127
+ end
128
+ end
129
+
130
+ def context_fetch(context, name)
131
+ context.code_lookup!(name).code_fetch(name)
132
+ rescue Error
133
+ nil
134
+ end
135
+
136
+ def expanded_arguments(value, context)
137
+ if value.nothing?
138
+ context.code_lookup!("rest").code_fetch("rest").code_to_list.raw
139
+ else
140
+ value.to_code.code_to_list.raw
141
+ end
142
+ end
65
143
  end
66
144
  end
67
145
  end
@@ -6,8 +6,10 @@ class Code
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
8
 
9
+ @has_value = parsed[:value].present?
9
10
  @value = Node::Code.new(parsed.delete(:value).presence)
10
11
  @name = parsed.delete(:name).presence
12
+ @operator = parsed.delete(:operator).presence
11
13
  end
12
14
 
13
15
  def evaluate(**args)
@@ -20,10 +22,22 @@ class Code
20
22
  end
21
23
  end
22
24
 
25
+ def operator
26
+ @operator.to_s
27
+ end
28
+
29
+ def expansion?
30
+ operator.present?
31
+ end
32
+
23
33
  def keyword?
24
34
  !!@name
25
35
  end
26
36
 
37
+ def value?
38
+ !!@has_value
39
+ end
40
+
27
41
  def regular?
28
42
  !keyword?
29
43
  end
@@ -21,11 +21,11 @@ class Code
21
21
  args
22
22
  end
23
23
  last = Object::Nothing.new
24
+ root_object = args.fetch(:root_object, args.fetch(:object))
24
25
 
25
26
  begin
26
27
  (@statements || []).each do |statement|
27
- last =
28
- statement.evaluate(**statement_args, object: Object::Global.new)
28
+ last = statement.evaluate(**statement_args, object: root_object)
29
29
  end
30
30
  rescue Error::Retry
31
31
  retry if control_flow_scope == :group
@@ -48,9 +48,10 @@ class Code
48
48
 
49
49
  def resolve(**args)
50
50
  last = Object::Nothing.new
51
+ root_object = args.fetch(:root_object, args.fetch(:object))
51
52
 
52
53
  (@statements || []).each do |statement|
53
- last = statement.resolve(**args, object: Object::Global.new)
54
+ last = statement.resolve(**args, object: root_object)
54
55
  end
55
56
 
56
57
  last
@@ -8,15 +8,13 @@ class Code
8
8
  def initialize(parsed)
9
9
  return if parsed.blank?
10
10
 
11
- @name =
12
- parsed.delete(:name).presence || parsed[:regular_splat].presence ||
13
- parsed[:keyword_splat].presence || parsed[:spread].presence ||
14
- parsed[:block].presence
11
+ @name = parsed.delete(:name).presence
15
12
  @keyword = parsed.delete(:keyword).present?
16
13
  @regular_splat = parsed.delete(:regular_splat).present?
17
14
  @keyword_splat = parsed.delete(:keyword_splat).present?
18
15
  @spread = parsed.delete(:spread).present?
19
16
  @block = parsed.delete(:block).present?
17
+ @blocks = parsed.delete(:blocks).present?
20
18
  @default = Code.new(parsed.delete(:default)) if parsed.key?(:default)
21
19
  end
22
20
 
@@ -48,6 +46,10 @@ class Code
48
46
  !!@block
49
47
  end
50
48
 
49
+ def blocks?
50
+ !!@blocks
51
+ end
52
+
51
53
  def to_h
52
54
  {
53
55
  name: name,
@@ -57,6 +59,7 @@ class Code
57
59
  keyword_splat?: keyword_splat?,
58
60
  spread?: spread?,
59
61
  block?: block?,
62
+ blocks?: blocks?,
60
63
  default: default
61
64
  }
62
65
  end
@@ -11,10 +11,40 @@ class Code
11
11
  end
12
12
 
13
13
  def evaluate(**args)
14
- ::Code::Object::List.new(
15
- (@elements || []).map { |element| element.evaluate(**args) }
14
+ list =
15
+ ::Code::Object::List.new(
16
+ (@elements || []).map { |element| element.evaluate(**args) }
17
+ )
18
+ constructor = literal_constructor(args.fetch(:context), "List")
19
+ return list unless constructor
20
+ if Array(args[:constructing_literal_classes]).include?(
21
+ ::Code::Object::List
22
+ )
23
+ return list
24
+ end
25
+
26
+ constructor.call(
27
+ **args,
28
+ constructing_literal_classes:
29
+ Array(args[:constructing_literal_classes]) + [::Code::Object::List],
30
+ operator: nil,
31
+ arguments: ::Code::Object::List.new([list]),
32
+ explicit_arguments: true
16
33
  )
17
34
  end
35
+
36
+ private
37
+
38
+ def literal_constructor(context, name)
39
+ return unless context.code_has_key?(name).truthy?
40
+
41
+ constructor = context.code_fetch(name)
42
+ return unless constructor.is_a?(::Code::Object::Function)
43
+ return unless constructor.parent.is_a?(::Code::Object::Class)
44
+ return unless constructor.parent.raw == ::Code::Object::List
45
+
46
+ constructor
47
+ end
18
48
  end
19
49
  end
20
50
  end
@@ -13,7 +13,8 @@ class Code
13
13
 
14
14
  def evaluate(**args)
15
15
  left = @left&.evaluate(**args) || Object::Nothing.new
16
- index_args = args.merge(object: args.fetch(:previous_object, args.fetch(:object)))
16
+ index_args =
17
+ args.merge(object: args.fetch(:previous_object, args.fetch(:object)))
17
18
 
18
19
  (@statements || []).reduce(left) do |object, statement|
19
20
  object.code_fetch(statement.evaluate(**index_args))
@@ -30,7 +31,8 @@ class Code
30
31
  Object::IdentifierList.new([left])
31
32
  end
32
33
 
33
- index_args = args.merge(object: args.fetch(:previous_object, args.fetch(:object)))
34
+ index_args =
35
+ args.merge(object: args.fetch(:previous_object, args.fetch(:object)))
34
36
 
35
37
  (@statements || []).each do |statement|
36
38
  list.code_append(statement.evaluate(**index_args))
@@ -3,28 +3,154 @@
3
3
  class Code
4
4
  class Object
5
5
  class Base64 < Object
6
+ CLASS_DOCUMENTATION = {
7
+ name: "Base64",
8
+ description: "encodes and decodes strings with base64 text formats.",
9
+ examples: [
10
+ "Base64.encode(:hello)",
11
+ "Base64.decode(Base64.encode(:hello))",
12
+ "Base64.urlsafe_decode(Base64.urlsafe_encode(\"???\"))"
13
+ ]
14
+ }.freeze
15
+ CLASS_FUNCTIONS = {
16
+ "encode" => {
17
+ name: "encode",
18
+ description: "returns base64 text with line breaks for a string.",
19
+ examples: [
20
+ "Base64.encode(:hello)",
21
+ "Base64.encode(:hello_world)",
22
+ "Base64.encode(\"123\")"
23
+ ]
24
+ },
25
+ "encode_64" => {
26
+ name: "encode_64",
27
+ description: "returns base64 text with line breaks for a string.",
28
+ examples: [
29
+ "Base64.encode_64(:hello)",
30
+ "Base64.encode_64(:hello_world)",
31
+ "Base64.encode_64(\"123\")"
32
+ ]
33
+ },
34
+ "decode" => {
35
+ name: "decode",
36
+ description: "returns a string decoded from base64 text.",
37
+ examples: [
38
+ "Base64.decode(\"aGVsbG8=\")",
39
+ "Base64.decode(Base64.encode(:hello))",
40
+ "Base64.decode(\"MTIz\")"
41
+ ]
42
+ },
43
+ "decode_64" => {
44
+ name: "decode_64",
45
+ description: "returns a string decoded from base64 text.",
46
+ examples: [
47
+ "Base64.decode_64(\"aGVsbG8=\")",
48
+ "Base64.decode_64(Base64.encode(:hello))",
49
+ "Base64.decode_64(\"MTIz\")"
50
+ ]
51
+ },
52
+ "strict_encode" => {
53
+ name: "strict_encode",
54
+ description: "returns base64 text without line breaks for a string.",
55
+ examples: [
56
+ "Base64.strict_encode(:hello)",
57
+ "Base64.strict_encode(:hello_world)",
58
+ "Base64.strict_encode(\"123\")"
59
+ ]
60
+ },
61
+ "strict_encode_64" => {
62
+ name: "strict_encode_64",
63
+ description: "returns base64 text without line breaks for a string.",
64
+ examples: [
65
+ "Base64.strict_encode_64(:hello)",
66
+ "Base64.strict_encode_64(:hello_world)",
67
+ "Base64.strict_encode_64(\"123\")"
68
+ ]
69
+ },
70
+ "strict_decode" => {
71
+ name: "strict_decode",
72
+ description: "returns a string decoded from strict base64 text.",
73
+ examples: [
74
+ "Base64.strict_decode(\"aGVsbG8=\")",
75
+ "Base64.strict_decode(Base64.strict_encode(:hello))",
76
+ "Base64.strict_decode(\"MTIz\")"
77
+ ]
78
+ },
79
+ "strict_decode_64" => {
80
+ name: "strict_decode_64",
81
+ description: "returns a string decoded from strict base64 text.",
82
+ examples: [
83
+ "Base64.strict_decode_64(\"aGVsbG8=\")",
84
+ "Base64.strict_decode_64(Base64.strict_encode(:hello))",
85
+ "Base64.strict_decode_64(\"MTIz\")"
86
+ ]
87
+ },
88
+ "urlsafe_encode" => {
89
+ name: "urlsafe_encode",
90
+ description: "returns url-safe base64 text for a string.",
91
+ examples: [
92
+ "Base64.urlsafe_encode(:hello)",
93
+ "Base64.urlsafe_encode(\">>>\")",
94
+ "Base64.urlsafe_encode(\"???\")"
95
+ ]
96
+ },
97
+ "url_safe_encode_64" => {
98
+ name: "url_safe_encode_64",
99
+ description: "returns url-safe base64 text for a string.",
100
+ examples: [
101
+ "Base64.url_safe_encode_64(:hello)",
102
+ "Base64.url_safe_encode_64(\">>>\")",
103
+ "Base64.url_safe_encode_64(\"???\")"
104
+ ]
105
+ },
106
+ "urlsafe_decode" => {
107
+ name: "urlsafe_decode",
108
+ description: "returns a string decoded from url-safe base64 text.",
109
+ examples: [
110
+ "Base64.urlsafe_decode(\"aGVsbG8=\")",
111
+ "Base64.urlsafe_decode(\"Pj4-\")",
112
+ "Base64.urlsafe_decode(\"Pz8_\")"
113
+ ]
114
+ },
115
+ "url_safe_decode_64" => {
116
+ name: "url_safe_decode_64",
117
+ description: "returns a string decoded from url-safe base64 text.",
118
+ examples: [
119
+ "Base64.url_safe_decode_64(\"aGVsbG8=\")",
120
+ "Base64.url_safe_decode_64(\"Pj4-\")",
121
+ "Base64.url_safe_decode_64(\"Pz8_\")"
122
+ ]
123
+ }
124
+ }.freeze
125
+
126
+ def self.function_documentation(scope)
127
+ return CLASS_FUNCTIONS if scope == :class
128
+
129
+ {}
130
+ end
131
+
6
132
  def self.call(**args)
7
133
  code_operator = args.fetch(:operator, nil).to_code
8
134
  code_arguments = args.fetch(:arguments, []).to_code
9
135
  code_value = code_arguments.code_first
10
136
 
11
137
  case code_operator.to_s
12
- when "encode"
138
+ when "encode", "encode_64"
13
139
  sig(args) { String }
14
140
  code_encode(code_value)
15
- when "decode"
141
+ when "decode", "decode_64"
16
142
  sig(args) { String }
17
143
  code_decode(code_value)
18
- when "strict_encode"
144
+ when "strict_encode", "strict_encode_64"
19
145
  sig(args) { String }
20
146
  code_strict_encode(code_value)
21
- when "strict_decode"
147
+ when "strict_decode", "strict_decode_64"
22
148
  sig(args) { String }
23
149
  code_strict_decode(code_value)
24
- when "urlsafe_encode"
150
+ when "urlsafe_encode", "url_safe_encode_64"
25
151
  sig(args) { String }
26
152
  code_urlsafe_encode(code_value)
27
- when "urlsafe_decode"
153
+ when "urlsafe_decode", "url_safe_decode_64"
28
154
  sig(args) { String }
29
155
  code_urlsafe_decode(code_value)
30
156
  else