tanshuku 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
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