tanshuku 0.0.14 → 0.0.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b280080f53f8fb1f57a0b05cd1f4549f81a8c5c6a893501eec056bf0ff49e894
4
- data.tar.gz: c2dea1c5782731a81c2f961186211cddff5c9494be925f1d395a53cea17a11c4
3
+ metadata.gz: 0324af7c609277e8e090c37de67cb5c6c86cfd6e72944f6b04d36f58e241e76f
4
+ data.tar.gz: '08ff837c3b7a985ab8cdc849b0bc2b8bda659b4863d5e2b6a6c1c10a8676c977'
5
5
  SHA512:
6
- metadata.gz: 8c96f4614d77af55d6a3889956967ab5244819071a0ec77d415df5af76fd288eefc0554cbb32b661ea7349fd5e8175201e02fe5309ec8dd53634eefa30508cc5
7
- data.tar.gz: 9f8ed89f16d6531f60303f03feded46ff98a35f5319bd6ec7b77e5526664fd830dad0da8eec51e8fbd7432d87702d88d34df9b1db1fdc03a4a04a006d87af3d2
6
+ metadata.gz: 9750293fcc5dc6baeb2cc5b3e6ab535a4207c6aaaba0a9c9dfa1647134ed04ac48421d87ef85261210618628ecbf36b654ccc63216ed9e769f062e701f1e5611
7
+ data.tar.gz: dcbf6e0c7cdda1284d5fadd1a7c9c96beb513e595c94e23902973634035d7c7ff5adbe145406f4cfdf22e5fe8a6c85fea6ba67bd8f95e03a569dae1692584823
data/README.md CHANGED
@@ -175,3 +175,20 @@ bin/rails db:migrate
175
175
  ### \*\* (anything you want) isn't implemented?
176
176
 
177
177
  Does Tanshuku have some missing features? Please [create an issue](https://github.com/kg8m/tanshuku/issues/new).
178
+
179
+ ## How to develop
180
+
181
+ 1. Fork this repository
182
+ 1. `git clone` your fork
183
+ 1. `bundle install`
184
+ 1. Update sources
185
+ 1. `rake`
186
+ 1. Fix `rake` errors if `rake` fails
187
+ 1. Create a pull request
188
+
189
+ ## How to release
190
+
191
+ 1. Make your repository fresh
192
+ 1. `bump current` and confirm the current version
193
+ 1. `bump patch`, `bump minor`, or `bump major`
194
+ 1. `rake release`
data/Rakefile CHANGED
@@ -21,10 +21,10 @@ namespace :yard do
21
21
  sh "yard server --reload"
22
22
  end
23
23
 
24
- desc "Generate YARD docs"
25
- task :generate do
26
- sh "yard --output-dir docs"
24
+ desc "Check YARD docs"
25
+ task :check do
26
+ sh "yard --no-output --no-cache --fail-on-warning"
27
27
  end
28
28
  end
29
29
 
30
- task default: %i[rubocop spec]
30
+ task default: %i[rubocop spec yard:check]
@@ -2,22 +2,30 @@
2
2
 
3
3
  require "active_record"
4
4
  require "addressable"
5
- require "digest/sha2"
6
5
  require "rack"
7
- require "securerandom"
8
6
 
9
7
  module Tanshuku
10
8
  # An +ActiveRecord::Base+ inherited class for a shortened URL. This class also have some logics for shortening URLs.
11
9
  class Url < ActiveRecord::Base
12
- DEFAULT_NAMESPACE = ""
10
+ # @!attribute [rw] url
11
+ # @return [String] Original, i.e., non-shortened, URL of the record.
12
+ #
13
+ # @!attribute [rw] hashed_url
14
+ # @return [String] A hashed string of the record's original URL.
15
+ # @note This attribute is used for uniqueness of the original URL.
16
+ # @api private
17
+ #
18
+ # @!attribute [rw] key
19
+ # @return [String] A unique key for the record.
20
+ #
21
+ # @!attribute [rw] created_at
22
+ # @return [ActiveSupport::TimeWithZone] A timestamp when the record is created.
13
23
 
14
- MAX_URL_LENGTH = 10_000
15
- URL_PATTERN = %r{\A(?:https?://\w+|/)}
16
- KEY_LENGTH = 20
24
+ DEFAULT_NAMESPACE = ""
17
25
 
18
26
  validates :url, :hashed_url, :key, presence: true
19
- validates :url, length: { maximum: MAX_URL_LENGTH }
20
- validates :url, format: { with: URL_PATTERN }, allow_blank: true
27
+ validates :url, length: { maximum: proc { Tanshuku.config.max_url_length } }
28
+ validates :url, format: { with: proc { Tanshuku.config.url_pattern } }, allow_blank: true
21
29
 
22
30
  # Don't validate uniqueness of unique attributes. Raise ActiveRecord::RecordNotUnique instead if the attributes get
23
31
  # duplicated. Then rescue the exception and try to retry.
@@ -34,8 +42,8 @@ module Tanshuku
34
42
  # +shorten("https://google.com")+ have the same result.
35
43
  #
36
44
  # @param original_url [String] The original, i.e., non-shortened, URL.
37
- # @param namespace: [String] A namespace for shorteting URL. Shortened URLs are unique in namespaces.
38
- # @param url_options: [Hash] An option for Rails' +url_for+.
45
+ # @param namespace [String] A namespace for shorteting URL. Shortened URLs are unique in namespaces.
46
+ # @param url_options [Hash] An option for Rails' +url_for+.
39
47
  #
40
48
  # @return [String] A shortened URL if succeeded to shorten the original URL.
41
49
  # @return [String] The original URL if failed to shorten it.
@@ -96,10 +104,10 @@ module Tanshuku
96
104
  # Finds a {Tanshuku::Url} record by a non-shortened URL.
97
105
  #
98
106
  # @param url [String] A non-shortened URL.
99
- # @param namespace: [String] A namespace for the URL.
107
+ # @param namespace [String] A namespace for the URL.
100
108
  #
101
109
  # @return [Tanshuku::Url] A {Tanshuku::Url} instance if found.
102
- # @reutnr [nil] +nil+ unless found.
110
+ # @return [nil] +nil+ unless found.
103
111
  def self.find_by_url(url, namespace: DEFAULT_NAMESPACE)
104
112
  normalized_url = normalize_url(url)
105
113
  hashed_url = hash_url(normalized_url, namespace:)
@@ -119,31 +127,35 @@ module Tanshuku
119
127
  parsed_url.normalize.to_s
120
128
  end
121
129
 
122
- # Hashes a URL with +Digest::SHA512.hexdigest+.
130
+ # Hashes a URL.
131
+ #
132
+ # @note This method calls {Tanshuku::Configuration#url_hasher}'s +call+ and returns its return value.
123
133
  #
124
134
  # @param url [String] A non-hashed URL.
125
- # @param namespace: [String] A namespace for the URL.
135
+ # @param namespace [String] A namespace for the URL.
126
136
  #
127
- # @return [String] A hashed 128-character string.
137
+ # @return [String] Depends on your {Tanshuku::Configuration#url_hasher} configuration.
128
138
  def self.hash_url(url, namespace: DEFAULT_NAMESPACE)
129
- Digest::SHA512.hexdigest(namespace.to_s + url)
139
+ Tanshuku.config.url_hasher.call(url, namespace:)
130
140
  end
131
141
 
132
- # Generates a key with +SecureRandom.alphanumeric+.
142
+ # Generates a unique key for a shortened URL.
143
+ #
144
+ # @note This method calls {Tanshuku::Configuration#key_generator}'s +call+ and returns its return value.
133
145
  #
134
- # @return [String] A 20-character alphanumeric string.
146
+ # @return [String] Depends on your {Tanshuku::Configuration#key_generator} configuration.
135
147
  def self.generate_key
136
- SecureRandom.alphanumeric(KEY_LENGTH)
148
+ Tanshuku.config.key_generator.call
137
149
  end
138
150
 
139
151
  # Reports an exception when failed to shorten a URL.
140
152
  #
141
153
  # @note This method calls {Tanshuku::Configuration#exception_reporter}'s +call+ and returns its return value.
142
154
  #
143
- # @param exception: [Exception] An error instance at shortening a URL.
144
- # @param original_url: [String] The original URL failed to shorten.
155
+ # @param exception [Exception] An error instance at shortening a URL.
156
+ # @param original_url [String] The original URL failed to shorten.
145
157
  #
146
- # @return [void]
158
+ # @return [void] Depends on your {Tanshuku::Configuration#exception_reporter} configuration.
147
159
  def self.report_exception(exception:, original_url:)
148
160
  Tanshuku.config.exception_reporter.call(exception:, original_url:)
149
161
  end
@@ -1,14 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "digest/sha2"
4
+ require "securerandom"
5
+
3
6
  module Tanshuku
4
7
  # A class for managing Tanshuku configurations.
5
8
  class Configuration
9
+ # The default object to hash a URL. Calls +Digest::SHA512.hexdigest+.
10
+ module DefaultUrlHasher
11
+ # Calls +Digest::SHA512.hexdigest+ with the given URL string and the given namespace.
12
+ #
13
+ # @param url [String] A URL to hash.
14
+ # @param namespace [String] A namespace for the URL's uniqueness.
15
+ #
16
+ # @return [String] A SHA512 digest string from the given url and namespace.
17
+ def self.call(url, namespace:)
18
+ Digest::SHA512.hexdigest("#{namespace}#{url}")
19
+ end
20
+ end
21
+
22
+ # The default unique key generator. Calls +SecureRandom.alphanumeric+ with {Tanshuku::Configuration#key_length}.
23
+ module DefaultKeyGenerator
24
+ # Calls +SecureRandom.alphanumeric+ and returns a string with length of {Tanshuku::Configuration#key_length}.
25
+ #
26
+ # @return [String] An alphanumeric string with length of {Tanshuku::Configuration#key_length}.
27
+ def self.call
28
+ SecureRandom.alphanumeric(Tanshuku.config.key_length)
29
+ end
30
+ end
31
+
6
32
  # The default error-reporter. Calls +Rails.logger.warn+.
7
33
  module DefaultExceptionReporter
8
- # The default error-reporting procedure. Calls +Rails.logger.warn+.
34
+ # Calls +Rails.logger.warn+ and logs the exception and the original URL.
9
35
  #
10
- # @param exception: [Exception] An error instance at shortening a URL.
11
- # @param original_url: [String] The original URL failed to shorten.
36
+ # @param exception [Exception] An error instance at shortening a URL.
37
+ # @param original_url [String] The original URL failed to shorten.
12
38
  #
13
39
  # @return [void]
14
40
  def self.call(exception:, original_url:)
@@ -35,12 +61,102 @@ module Tanshuku
35
61
  # end
36
62
  attribute :default_url_options, default: {}
37
63
 
64
+ # @!attribute [rw] max_url_length
65
+ # Maximum length of {Tanshuku::Url#url}. Defaults to +10,000+.
66
+ #
67
+ # @return [Integer]
68
+ # @return [void] If you set an invalid object.
69
+ #
70
+ # @note
71
+ # The example below means that {Tanshuku::Url#url} can have a URL string with less than or equal to 20,000
72
+ # characters.
73
+ #
74
+ # @example
75
+ # # config/initializers/tanshuku.rb
76
+ # Tanshuku.configure do |config|
77
+ # config.max_url_length = 20_000
78
+ # end
79
+ attribute :max_url_length, :integer, default: 10_000
80
+
81
+ # @!attribute [rw] url_pattern
82
+ # Allowed pattern of {Tanshuku::Url#url}. Defaults to <code>%r{\A(?:https?://\w+|/)}</code>. This default value
83
+ # forces a URL to start with "http://" or "https://", or to be an absolute path without scheme.
84
+ #
85
+ # @return [Regexp]
86
+ # @return [void] If you set an invalid object.
87
+ #
88
+ # @note
89
+ # The example below means that {Tanshuku::Url#url} should start with a slash +/+.
90
+ #
91
+ # @example
92
+ # # config/initializers/tanshuku.rb
93
+ # Tanshuku.configure do |config|
94
+ # config.url_pattern = /\A\//
95
+ # end
96
+ attribute :url_pattern, default: %r{\A(?:https?://\w+|/)}
97
+
98
+ # @!attribute [rw] key_length
99
+ # Length of {Tanshuku::Url#key} when {Tanshuku::Configuration#key_generator} is
100
+ # {Tanshuku::Configuration::DefaultKeyGenerator}. Defaults to +20+.
101
+ #
102
+ # @return [Integer]
103
+ # @return [void] If you set an invalid object.
104
+ #
105
+ # @note Don't forget to fix the limit of the +tanshuku_urls.key+ column if you change this value.
106
+ #
107
+ # @note
108
+ # The example below means that {Tanshuku::Url#key} has 10-char string.
109
+ #
110
+ # @example
111
+ # # config/initializers/tanshuku.rb
112
+ # Tanshuku.configure do |config|
113
+ # config.key_length = 10
114
+ # end
115
+ attribute :key_length, :integer, default: 20
116
+
117
+ # @!attribute [rw] url_hasher
118
+ # A class, module, or object to hash a URL. This should respond to +#call+ with a required positional argument
119
+ # +url+ and a required keyword argument +namespace:+. Defaults to {Tanshuku::Configuration::DefaultUrlHasher}.
120
+ #
121
+ # @return [#call]
122
+ # A class, module, or object that responds to +#call+ with a required positional argument +url+ and a required
123
+ # keyword argument +namespace:+.
124
+ # @return [void] If you set an invalid object.
125
+ #
126
+ # @note The example below means that URLs are hashed with +Digest::SHA256.hexdigest+.
127
+ #
128
+ # @example
129
+ # # config/initializers/tanshuku.rb
130
+ # Tanshuku.configure do |config|
131
+ # config.url_hasher = ->(url, namespace:) { Digest::SHA256.hexdigest("#{namespace}#{url}") }
132
+ # end
133
+ attribute :url_hasher, default: DefaultUrlHasher
134
+
135
+ # @!attribute [rw] key_generator
136
+ # A class, module, or object to generate a unique key for shortened URLs. This should respond to +#call+ without
137
+ # any arguments. Defaults to {Tanshuku::Configuration::DefaultKeyGenerator}.
138
+ #
139
+ # @return [#call]
140
+ # A class, module, or object that responds to +#call+ without any arguments.
141
+ # @return [void] If you set an invalid object.
142
+ #
143
+ # @note The example below means that unique keys for shortened URLs are generated by +SecureRandom.uuid+.
144
+ #
145
+ # @example
146
+ # # config/initializers/tanshuku.rb
147
+ # Tanshuku.configure do |config|
148
+ # config.key_generator = -> { SecureRandom.uuid }
149
+ # end
150
+ attribute :key_generator, default: DefaultKeyGenerator
151
+
38
152
  # @!attribute [rw] exception_reporter
39
153
  # A error-reporter class, module, or object used when shortening a URL fails. This should respond to +#call+ with
40
- # keyword arguments +exception:+ and +original_url:+. Defaults to
154
+ # required keyword arguments +exception:+ and +original_url:+. Defaults to
41
155
  # {Tanshuku::Configuration::DefaultExceptionReporter}.
42
156
  #
43
- # @return [#call] An object that responds to +#call+ with keyword arguments +exception:+ and +original_url:+.
157
+ # @return [#call]
158
+ # A class, module, or object that responds to +#call+ with required keyword arguments +exception:+ and
159
+ # +original_url:+.
44
160
  # @return [void] If you set an invalid object.
45
161
  #
46
162
  # @note The example below means that an exception and a URL will be reported to Sentry (https://sentry.io).
@@ -67,6 +183,8 @@ module Tanshuku
67
183
  #
68
184
  # @return [void]
69
185
  #
186
+ # @note Use {Tanshuku.configure} as a public API for configuration.
187
+ #
70
188
  # @api private
71
189
  def configure
72
190
  @mutex.synchronize do
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tanshuku
4
- VERSION = "0.0.14"
4
+ VERSION = "0.0.15"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tanshuku
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - kg8m
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-26 00:00:00.000000000 Z
11
+ date: 2023-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable