lipwa 0.1.2 → 0.1.4

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +219 -204
  4. data/lib/lipwa/auth_strategies/api_key.rb +28 -0
  5. data/lib/lipwa/auth_strategies/base.rb +4 -0
  6. data/lib/lipwa/auth_strategies/bearer_token.rb +5 -0
  7. data/lib/lipwa/auth_strategies/jenga.rb +58 -0
  8. data/lib/lipwa/auth_strategies.rb +2 -0
  9. data/lib/lipwa/capabilities/authorize.rb +26 -0
  10. data/lib/lipwa/capabilities/bank_transfer.rb +66 -0
  11. data/lib/lipwa/capabilities/c2b.rb +11 -10
  12. data/lib/lipwa/capabilities/capture.rb +25 -0
  13. data/lib/lipwa/capabilities/disbursement.rb +16 -17
  14. data/lib/lipwa/capabilities/lightning_invoice.rb +75 -0
  15. data/lib/lipwa/capabilities/lightning_payment.rb +71 -0
  16. data/lib/lipwa/capabilities/purchase.rb +26 -0
  17. data/lib/lipwa/capabilities/refund.rb +14 -14
  18. data/lib/lipwa/capabilities/status_query.rb +21 -12
  19. data/lib/lipwa/capabilities/stk_push.rb +8 -5
  20. data/lib/lipwa/capabilities/void.rb +25 -0
  21. data/lib/lipwa/configuration_snapshot.rb +50 -0
  22. data/lib/lipwa/context.rb +60 -0
  23. data/lib/lipwa/contracts/bank_transfer_contract.rb +61 -0
  24. data/lib/lipwa/contracts/card_payment_contract.rb +59 -0
  25. data/lib/lipwa/contracts/card_transaction_contract.rb +21 -0
  26. data/lib/lipwa/contracts/lightning_invoice_check_contract.rb +18 -0
  27. data/lib/lipwa/contracts/lightning_invoice_contract.rb +27 -0
  28. data/lib/lipwa/contracts/lightning_payment_check_contract.rb +18 -0
  29. data/lib/lipwa/contracts/lightning_payment_contract.rb +14 -0
  30. data/lib/lipwa/contracts/status_query_contract.rb +29 -6
  31. data/lib/lipwa/errors.rb +4 -2
  32. data/lib/lipwa/gateway.rb +24 -5
  33. data/lib/lipwa/gateways/coop_bank/auth.rb +68 -0
  34. data/lib/lipwa/gateways/coop_bank.rb +115 -0
  35. data/lib/lipwa/gateways/flutterwave.rb +160 -0
  36. data/lib/lipwa/gateways/jenga/auth.rb +76 -0
  37. data/lib/lipwa/gateways/jenga.rb +282 -0
  38. data/lib/lipwa/gateways/lnbits.rb +67 -0
  39. data/lib/lipwa/gateways/mpesa/auth.rb +18 -2
  40. data/lib/lipwa/gateways/mpesa.rb +16 -11
  41. data/lib/lipwa/gateways/paystack.rb +119 -0
  42. data/lib/lipwa/gateways/pesapal/auth.rb +72 -0
  43. data/lib/lipwa/gateways/pesapal.rb +123 -0
  44. data/lib/lipwa/gateways.rb +7 -1
  45. data/lib/lipwa/http_adapter.rb +56 -17
  46. data/lib/lipwa/logging.rb +100 -0
  47. data/lib/lipwa/money.rb +33 -4
  48. data/lib/lipwa/types.rb +3 -3
  49. data/lib/lipwa/version.rb +1 -1
  50. data/lib/lipwa/webhooks/coop_bank.rb +28 -0
  51. data/lib/lipwa/webhooks/jenga.rb +55 -0
  52. data/lib/lipwa/webhooks/lnbits.rb +46 -0
  53. data/lib/lipwa.rb +29 -0
  54. metadata +32 -4
  55. data/CODE_OF_CONDUCT.md +0 -10
  56. data/Rakefile +0 -12
  57. data/sig/lipwa.rbs +0 -4
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+
6
+ module Lipwa
7
+ module Logging
8
+ REDACTED = "[REDACTED]"
9
+
10
+ # Produces sanitized copies of nested payloads without mutating caller data.
11
+ module Redactor
12
+ SECRET_NAMES = "authorization|signature|cookie|api[_-]?key|access[_-]?token|" \
13
+ "refresh[_-]?token|token|consumer[_-]?key|client[_-]?id|" \
14
+ "secret|password|passkey|" \
15
+ "security[_-]?credential|private[_-]?key|admin[_-]?key|invoice[_-]?key|encryption[_-]?key"
16
+ SENSITIVE_KEY = /(?:#{SECRET_NAMES})/i
17
+ STRING_PATTERNS = [
18
+ /((?:authorization|proxy-authorization|signature)\s*:\s*)[^\r\n,]+/i,
19
+ /((?:^|[?&])(?:#{SECRET_NAMES})=)[^&#\s]+/i,
20
+ /(["']?(?:#{SECRET_NAMES})["']?\s*[:=]\s*["'])[^"']*(["'])/i
21
+ ].freeze
22
+
23
+ module_function
24
+
25
+ def call(value, key: nil) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
26
+ return REDACTED if sensitive_key?(key)
27
+
28
+ case value
29
+ when Hash
30
+ value.each_with_object({}) do |(child_key, child_value), copy|
31
+ copy[child_key] = call(child_value, key: child_key)
32
+ end
33
+ when Array then value.map { |item| call(item) }
34
+ when String then redact_string(value)
35
+ when Exception then { class: value.class.name, message: redact_string(value.message) }
36
+ else value
37
+ end
38
+ end
39
+
40
+ def sensitive_key?(key) = key&.to_s&.match?(SENSITIVE_KEY)
41
+
42
+ def redact_string(value)
43
+ STRING_PATTERNS.reduce(value.dup) do |redacted, pattern|
44
+ redacted.gsub(pattern) { "#{Regexp.last_match(1)}#{REDACTED}#{Regexp.last_match(2)}" }
45
+ end
46
+ end
47
+ end
48
+
49
+ # Faraday middleware that emits one structured, sanitized event per call.
50
+ class Middleware < Faraday::Middleware
51
+ def initialize(app, logger)
52
+ super(app)
53
+ @logger = logger
54
+ end
55
+
56
+ def call(env)
57
+ started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
58
+ @app.call(env).on_complete { |completed| log(completed, started_at) }
59
+ rescue StandardError => e
60
+ log(env, started_at, error: e)
61
+ raise
62
+ end
63
+
64
+ private
65
+
66
+ def log(env, started_at, error: nil) # rubocop:disable Metrics/AbcSize
67
+ event = {
68
+ event: "lipwa.http", method: env.method&.to_s&.upcase,
69
+ url: sanitized_url(env.url), status: env.status,
70
+ duration_ms: elapsed_ms(started_at),
71
+ request: { headers: Redactor.call(env.request_headers.to_h), body: redact_body(env.request_body) },
72
+ response: { headers: Redactor.call(env.response_headers.to_h), body: redact_body(env.response_body) }
73
+ }
74
+ event[:error] = Redactor.call(error) if error
75
+ @logger.public_send(error || env.status.to_i >= 400 ? :error : :info, event)
76
+ end
77
+
78
+ def sanitized_url(url)
79
+ return unless url
80
+
81
+ copy = url.dup
82
+ copy.user = REDACTED if copy.user
83
+ copy.password = REDACTED if copy.password
84
+ copy.query = Redactor.redact_string(copy.query) if copy.query
85
+ copy.to_s
86
+ end
87
+
88
+ def redact_body(body)
89
+ parsed = body.is_a?(String) ? JSON.parse(body) : body
90
+ Redactor.call(parsed)
91
+ rescue JSON::ParserError
92
+ Redactor.call(body)
93
+ end
94
+
95
+ def elapsed_ms(started_at)
96
+ ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at) * 1000).round(1)
97
+ end
98
+ end
99
+ end
100
+ end
data/lib/lipwa/money.rb CHANGED
@@ -4,10 +4,10 @@ require "dry/struct"
4
4
  require_relative "types"
5
5
 
6
6
  module Lipwa
7
- # Immutable representation of an amount in minor currency units.
8
- # KES has no subunit in practice, but we keep minor units as the
9
- # storage form so other currencies fit the same shape later.
7
+ # Immutable, decimal representation of an amount in one currency.
10
8
  class Money < Dry::Struct
9
+ include Comparable
10
+
11
11
  attribute :amount, Types::Amount
12
12
  attribute :currency, Types::Currency.default("KES")
13
13
 
@@ -21,16 +21,45 @@ module Lipwa
21
21
  self.class.new(amount: amount - other.amount, currency: currency)
22
22
  end
23
23
 
24
+ def *(other)
25
+ self.class.new(amount: amount * decimal_scalar(other), currency: currency)
26
+ end
27
+
28
+ def /(other)
29
+ divisor = decimal_scalar(other)
30
+ raise ZeroDivisionError, "divided by 0" if divisor.zero?
31
+
32
+ self.class.new(amount: amount / divisor, currency: currency)
33
+ end
34
+
35
+ def <=>(other)
36
+ return nil unless other.is_a?(self.class)
37
+
38
+ assert_same_currency!(other)
39
+ amount <=> other.amount
40
+ end
41
+
42
+ def zero?
43
+ amount.zero?
44
+ end
45
+
24
46
  def to_s
25
- "#{amount} #{currency}"
47
+ "#{amount.to_s("F")} #{currency}"
26
48
  end
27
49
 
28
50
  private
29
51
 
30
52
  def assert_same_currency!(other)
53
+ raise TypeError, "expected #{self.class}, got #{other.class}" unless other.is_a?(self.class)
31
54
  return if currency == other.currency
32
55
 
33
56
  raise ArgumentError, "currency mismatch: #{currency} vs #{other.currency}"
34
57
  end
58
+
59
+ def decimal_scalar(value)
60
+ Types::Coercible::Decimal[value]
61
+ rescue Dry::Types::CoercionError, Dry::Types::ConstraintError
62
+ raise TypeError, "expected a numeric scalar, got #{value.inspect}"
63
+ end
35
64
  end
36
65
  end
data/lib/lipwa/types.rb CHANGED
@@ -7,9 +7,9 @@ module Lipwa
7
7
  module Types
8
8
  include Dry.Types()
9
9
 
10
- # Amounts are always integers in minor currency units (e.g. cents,
11
- # or whole KES since M-Pesa has no subunit) to avoid float math.
12
- Amount = Types::Strict::Integer.constrained(gteq: 0)
10
+ # BigDecimal-backed amounts avoid binary floating-point errors while
11
+ # accepting the numeric and string inputs commonly received from APIs.
12
+ Amount = Types::Coercible::Decimal.constrained(gteq: 0)
13
13
 
14
14
  Currency = Types::Strict::String.constrained(format: /\A[A-Z]{3}\z/)
15
15
 
data/lib/lipwa/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lipwa
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../webhook"
4
+
5
+ module Lipwa
6
+ module Webhooks
7
+ # Normalizes Co-op Bank transaction callbacks into WebhookEvent.
8
+ module CoopBank
9
+ module_function
10
+
11
+ def call(body:, headers: {}) # rubocop:disable Lint/UnusedMethodArgument
12
+ payload = body.is_a?(String) ? JSON.parse(body) : body
13
+ code = payload["MessageCode"]
14
+
15
+ Lipwa::WebhookEvent.new(
16
+ provider: :coop_bank,
17
+ event_type: :transaction_status,
18
+ success: code.to_s == "0",
19
+ provider_reference: payload["MessageReference"]&.to_s,
20
+ message: payload["MessageDescription"]&.to_s,
21
+ raw: payload
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ Lipwa::Webhook.register(:coop_bank, Lipwa::Webhooks::CoopBank)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+ require "openssl"
5
+ require_relative "../webhook"
6
+
7
+ module Lipwa
8
+ module Webhooks
9
+ # Parses Jenga HQ receive-payment Instant Payment Notifications (IPNs).
10
+ module Jenga
11
+ module_function
12
+
13
+ # rubocop:disable Metrics/MethodLength
14
+ def call(body:, headers: {})
15
+ payload = parse(body)
16
+ transaction = payload.fetch("transaction", {})
17
+ authorization = header(headers, "Authorization")
18
+
19
+ Lipwa::WebhookEvent.new(
20
+ provider: :jenga,
21
+ event_type: :receive_payment,
22
+ success: transaction["status"].to_s.casecmp?("SUCCESS"),
23
+ provider_reference: transaction["reference"],
24
+ message: transaction["remarks"],
25
+ raw: payload,
26
+ verifier: lambda do |raw:, username:, password:, **|
27
+ verify_signature(raw: raw, authorization: authorization, username: username, password: password)
28
+ end
29
+ )
30
+ end
31
+ # rubocop:enable Metrics/MethodLength
32
+
33
+ def parse(body)
34
+ body.is_a?(String) ? JSON.parse(body) : body
35
+ end
36
+
37
+ def verify_signature(raw:, authorization:, username:, password:) # rubocop:disable Lint/UnusedMethodArgument
38
+ return false unless authorization.is_a?(String) && username.is_a?(String) && password.is_a?(String)
39
+ return false if username.strip.empty? || password.strip.empty?
40
+
41
+ expected = "Basic #{Base64.strict_encode64("#{username}:#{password}")}"
42
+ return false unless authorization.bytesize == expected.bytesize
43
+
44
+ OpenSSL.fixed_length_secure_compare(authorization, expected)
45
+ end
46
+
47
+ def header(headers, name)
48
+ pair = headers.find { |key, _| key.to_s.casecmp?(name) }
49
+ pair&.last
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ Lipwa::Webhook.register(:jenga, Lipwa::Webhooks::Jenga)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+ require_relative "../webhook"
5
+
6
+ module Lipwa
7
+ module Webhooks
8
+ # Parses LNbits invoice-payment callbacks. LNbits does not sign webhook
9
+ # bodies by default; the verifier compares a per-invoice token supplied in
10
+ # the webhook URL instead. Treat the callback only as a notification and
11
+ # independently confirm payment with #check_invoice before crediting it.
12
+ module Lnbits
13
+ module_function
14
+
15
+ def call(body:, headers: {}) # rubocop:disable Lint/UnusedMethodArgument
16
+ payload = parse(body)
17
+
18
+ Lipwa::WebhookEvent.new(
19
+ provider: :lnbits,
20
+ event_type: :payment,
21
+ success: !payload.key?("paid") || payload["paid"] == true,
22
+ provider_reference: payload.fetch("payment_hash"),
23
+ message: payload["memo"],
24
+ raw: payload,
25
+ verifier: method(:verify_signature)
26
+ )
27
+ end
28
+
29
+ def parse(body)
30
+ body.is_a?(String) ? JSON.parse(body) : body
31
+ end
32
+
33
+ # This verifies knowledge of a shared URL token, not authenticity of the
34
+ # body. The ** passthrough preserves the API for a future HMAC mode.
35
+ def verify_signature(raw: nil, expected_token: nil, provided_token: nil, **) # rubocop:disable Lint/UnusedMethodArgument
36
+ return false unless expected_token.is_a?(String) && provided_token.is_a?(String)
37
+ return false if expected_token.strip.empty?
38
+ return false unless expected_token.bytesize == provided_token.bytesize
39
+
40
+ OpenSSL.fixed_length_secure_compare(expected_token, provided_token)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ Lipwa::Webhook.register(:lnbits, Lipwa::Webhooks::Lnbits)
data/lib/lipwa.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "lipwa/version"
4
4
  require_relative "lipwa/errors"
5
+ require_relative "lipwa/logging"
5
6
  require_relative "lipwa/types"
6
7
  require_relative "lipwa/money"
7
8
  require_relative "lipwa/response"
@@ -11,8 +12,12 @@ require_relative "lipwa/configuration"
11
12
  require_relative "lipwa/capability"
12
13
  require_relative "lipwa/gateway"
13
14
  require_relative "lipwa/gateways"
15
+ require_relative "lipwa/context"
14
16
  require_relative "lipwa/webhook"
15
17
  require_relative "lipwa/webhooks/mpesa"
18
+ require_relative "lipwa/webhooks/jenga"
19
+ require_relative "lipwa/webhooks/coop_bank"
20
+ require_relative "lipwa/webhooks/lnbits"
16
21
  require_relative "lipwa/contracts/c2b_register_urls_contract"
17
22
  require_relative "lipwa/contracts/c2b_simulate_contract"
18
23
  require_relative "lipwa/capabilities/c2b"
@@ -22,10 +27,34 @@ require_relative "lipwa/contracts/disbursement_contract"
22
27
  require_relative "lipwa/capabilities/disbursement"
23
28
  require_relative "lipwa/contracts/status_query_contract"
24
29
  require_relative "lipwa/capabilities/status_query"
30
+ require_relative "lipwa/contracts/lightning_invoice_contract"
31
+ require_relative "lipwa/contracts/lightning_invoice_check_contract"
32
+ require_relative "lipwa/contracts/lightning_payment_contract"
33
+ require_relative "lipwa/contracts/lightning_payment_check_contract"
34
+ require_relative "lipwa/capabilities/lightning_invoice"
35
+ require_relative "lipwa/capabilities/lightning_payment"
36
+ require_relative "lipwa/gateways/lnbits"
37
+ require_relative "lipwa/contracts/bank_transfer_contract"
38
+ require_relative "lipwa/capabilities/bank_transfer"
39
+ require_relative "lipwa/contracts/card_payment_contract"
40
+ require_relative "lipwa/contracts/card_transaction_contract"
41
+ require_relative "lipwa/capabilities/purchase"
42
+ require_relative "lipwa/capabilities/authorize"
43
+ require_relative "lipwa/capabilities/capture"
44
+ require_relative "lipwa/capabilities/void"
25
45
  require_relative "lipwa/gateways/mpesa"
46
+ require_relative "lipwa/gateways/coop_bank"
26
47
 
48
+ require_relative "lipwa/gateways/jenga"
49
+ require_relative "lipwa/gateways/pesapal"
50
+ require_relative "lipwa/gateways/flutterwave"
51
+ require_relative "lipwa/gateways/paystack"
27
52
  # Unified payment gateway abstraction for African payment providers.
28
53
  module Lipwa
54
+ def self.context(&block)
55
+ Context.new(&block)
56
+ end
57
+
29
58
  def self.gateway(name)
30
59
  Gateways[name]
31
60
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lipwa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Oguda
@@ -147,42 +147,70 @@ extensions: []
147
147
  extra_rdoc_files: []
148
148
  files:
149
149
  - CHANGELOG.md
150
- - CODE_OF_CONDUCT.md
151
150
  - LICENSE.txt
152
151
  - README.md
153
- - Rakefile
154
152
  - lib/lipwa.rb
155
153
  - lib/lipwa/auth_strategies.rb
154
+ - lib/lipwa/auth_strategies/api_key.rb
156
155
  - lib/lipwa/auth_strategies/base.rb
157
156
  - lib/lipwa/auth_strategies/bearer_token.rb
157
+ - lib/lipwa/auth_strategies/jenga.rb
158
158
  - lib/lipwa/auth_strategies/none.rb
159
+ - lib/lipwa/capabilities/authorize.rb
160
+ - lib/lipwa/capabilities/bank_transfer.rb
159
161
  - lib/lipwa/capabilities/c2b.rb
162
+ - lib/lipwa/capabilities/capture.rb
160
163
  - lib/lipwa/capabilities/disbursement.rb
164
+ - lib/lipwa/capabilities/lightning_invoice.rb
165
+ - lib/lipwa/capabilities/lightning_payment.rb
166
+ - lib/lipwa/capabilities/purchase.rb
161
167
  - lib/lipwa/capabilities/refund.rb
162
168
  - lib/lipwa/capabilities/status_query.rb
163
169
  - lib/lipwa/capabilities/stk_push.rb
170
+ - lib/lipwa/capabilities/void.rb
164
171
  - lib/lipwa/capability.rb
165
172
  - lib/lipwa/configuration.rb
173
+ - lib/lipwa/configuration_snapshot.rb
174
+ - lib/lipwa/context.rb
175
+ - lib/lipwa/contracts/bank_transfer_contract.rb
166
176
  - lib/lipwa/contracts/c2b_register_urls_contract.rb
167
177
  - lib/lipwa/contracts/c2b_simulate_contract.rb
178
+ - lib/lipwa/contracts/card_payment_contract.rb
179
+ - lib/lipwa/contracts/card_transaction_contract.rb
168
180
  - lib/lipwa/contracts/disbursement_contract.rb
181
+ - lib/lipwa/contracts/lightning_invoice_check_contract.rb
182
+ - lib/lipwa/contracts/lightning_invoice_contract.rb
183
+ - lib/lipwa/contracts/lightning_payment_check_contract.rb
184
+ - lib/lipwa/contracts/lightning_payment_contract.rb
169
185
  - lib/lipwa/contracts/refund_contract.rb
170
186
  - lib/lipwa/contracts/status_query_contract.rb
171
187
  - lib/lipwa/contracts/stk_push_contract.rb
172
188
  - lib/lipwa/errors.rb
173
189
  - lib/lipwa/gateway.rb
174
190
  - lib/lipwa/gateways.rb
191
+ - lib/lipwa/gateways/coop_bank.rb
192
+ - lib/lipwa/gateways/coop_bank/auth.rb
193
+ - lib/lipwa/gateways/flutterwave.rb
194
+ - lib/lipwa/gateways/jenga.rb
195
+ - lib/lipwa/gateways/jenga/auth.rb
196
+ - lib/lipwa/gateways/lnbits.rb
175
197
  - lib/lipwa/gateways/mpesa.rb
176
198
  - lib/lipwa/gateways/mpesa/auth.rb
177
199
  - lib/lipwa/gateways/mpesa/security_credential.rb
200
+ - lib/lipwa/gateways/paystack.rb
201
+ - lib/lipwa/gateways/pesapal.rb
202
+ - lib/lipwa/gateways/pesapal/auth.rb
178
203
  - lib/lipwa/http_adapter.rb
204
+ - lib/lipwa/logging.rb
179
205
  - lib/lipwa/money.rb
180
206
  - lib/lipwa/response.rb
181
207
  - lib/lipwa/types.rb
182
208
  - lib/lipwa/version.rb
183
209
  - lib/lipwa/webhook.rb
210
+ - lib/lipwa/webhooks/coop_bank.rb
211
+ - lib/lipwa/webhooks/jenga.rb
212
+ - lib/lipwa/webhooks/lnbits.rb
184
213
  - lib/lipwa/webhooks/mpesa.rb
185
- - sig/lipwa.rbs
186
214
  homepage: https://github.com/kamalogudah/lipwa
187
215
  licenses:
188
216
  - MIT
data/CODE_OF_CONDUCT.md DELETED
@@ -1,10 +0,0 @@
1
- # Code of Conduct
2
-
3
- "lipwa" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
4
-
5
- * Participants will be tolerant of opposing views.
6
- * Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
7
- * When interpreting the words and actions of others, participants should always assume good intentions.
8
- * Behaviour which can be reasonably considered harassment will not be tolerated.
9
-
10
- If you have any concerns about behaviour within this project, please contact us at ["mcpaul2058@gmail.com"](mailto:"mcpaul2058@gmail.com").
data/Rakefile DELETED
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "minitest/test_task"
5
-
6
- Minitest::TestTask.create
7
-
8
- require "rubocop/rake_task"
9
-
10
- RuboCop::RakeTask.new
11
-
12
- task default: %i[test rubocop]
data/sig/lipwa.rbs DELETED
@@ -1,4 +0,0 @@
1
- module Lipwa
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end