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 +4 -4
- data/README.md +17 -0
- data/Rakefile +4 -4
- data/app/models/tanshuku/url.rb +34 -22
- data/lib/tanshuku/configuration.rb +123 -5
- data/lib/tanshuku/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0324af7c609277e8e090c37de67cb5c6c86cfd6e72944f6b04d36f58e241e76f
|
4
|
+
data.tar.gz: '08ff837c3b7a985ab8cdc849b0bc2b8bda659b4863d5e2b6a6c1c10a8676c977'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 "
|
25
|
-
task :
|
26
|
-
sh "yard --output-
|
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]
|
data/app/models/tanshuku/url.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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:
|
20
|
-
validates :url, format: { with:
|
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
|
38
|
-
# @param url_options
|
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
|
107
|
+
# @param namespace [String] A namespace for the URL.
|
100
108
|
#
|
101
109
|
# @return [Tanshuku::Url] A {Tanshuku::Url} instance if found.
|
102
|
-
# @
|
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
|
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
|
135
|
+
# @param namespace [String] A namespace for the URL.
|
126
136
|
#
|
127
|
-
# @return [String]
|
137
|
+
# @return [String] Depends on your {Tanshuku::Configuration#url_hasher} configuration.
|
128
138
|
def self.hash_url(url, namespace: DEFAULT_NAMESPACE)
|
129
|
-
|
139
|
+
Tanshuku.config.url_hasher.call(url, namespace:)
|
130
140
|
end
|
131
141
|
|
132
|
-
# Generates a key
|
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]
|
146
|
+
# @return [String] Depends on your {Tanshuku::Configuration#key_generator} configuration.
|
135
147
|
def self.generate_key
|
136
|
-
|
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
|
144
|
-
# @param original_url
|
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
|
-
#
|
34
|
+
# Calls +Rails.logger.warn+ and logs the exception and the original URL.
|
9
35
|
#
|
10
|
-
# @param exception
|
11
|
-
# @param original_url
|
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]
|
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
|
data/lib/tanshuku/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2023-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|