dynamic_links 0.1.0

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 (34) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +66 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/dynamic_links_manifest.js +1 -0
  5. data/app/assets/stylesheets/dynamic_links/application.css +15 -0
  6. data/app/controllers/dynamic_links/application_controller.rb +4 -0
  7. data/app/controllers/dynamic_links/v1/short_links_controller.rb +14 -0
  8. data/app/helpers/dynamic_links/application_helper.rb +4 -0
  9. data/app/jobs/dynamic_links/application_job.rb +4 -0
  10. data/app/jobs/dynamic_links/generate_short_links_job.rb +31 -0
  11. data/app/mailers/dynamic_links/application_mailer.rb +6 -0
  12. data/app/models/dynamic_links/application_record.rb +5 -0
  13. data/app/models/dynamic_links/client.rb +21 -0
  14. data/app/models/dynamic_links/shortened_url.rb +25 -0
  15. data/app/views/layouts/dynamic_links/application.html.erb +15 -0
  16. data/config/routes.rb +8 -0
  17. data/db/migrate/20231228165744_create_dynamic_links_clients.rb +13 -0
  18. data/db/migrate/20231228175142_create_dynamic_links_shortened_urls.rb +21 -0
  19. data/lib/dynamic_links/configuration.rb +10 -0
  20. data/lib/dynamic_links/engine.rb +5 -0
  21. data/lib/dynamic_links/shortening_strategies/base_strategy.rb +28 -0
  22. data/lib/dynamic_links/shortening_strategies/crc32_strategy.rb +19 -0
  23. data/lib/dynamic_links/shortening_strategies/md5_strategy.rb +20 -0
  24. data/lib/dynamic_links/shortening_strategies/mock_strategy.rb +10 -0
  25. data/lib/dynamic_links/shortening_strategies/nano_id_strategy.rb +21 -0
  26. data/lib/dynamic_links/shortening_strategies/redis_counter_strategy.rb +31 -0
  27. data/lib/dynamic_links/shortening_strategies/sha256_strategy.rb +20 -0
  28. data/lib/dynamic_links/strategy_factory.rb +23 -0
  29. data/lib/dynamic_links/version.rb +3 -0
  30. data/lib/dynamic_links.rb +53 -0
  31. data/lib/generators/dynamic_links/add_kgs_migration_generator.rb +16 -0
  32. data/lib/generators/dynamic_links/templates/migration_template.rb +6 -0
  33. data/lib/tasks/dynamic_links_tasks.rake +4 -0
  34. metadata +147 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f8be4269ba92cfbec08c29ec6a6a871383b8470736057204fa24234ebfc70a98
4
+ data.tar.gz: 90a2df3615def525638fc53eeb23eef0a367d0137993b6303630d7d868ac3443
5
+ SHA512:
6
+ metadata.gz: 3ca6e9c92116542c9df6895e861843c03e951cb7e87bf567bc189b4811f8fb6cf95e097123b4569843ea18f8780289e1bec70b2de2a8bd92532f929277e0578e
7
+ data.tar.gz: 50e65b566b1b36f9b169f0a7c35610720027f030c31d4fd7fe861ee077ea1b5c043391a51caf4f34c612f13456fdcf16cbb95d39a019c69f65bb2676bc2d7fd7
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # DynamicLinks
2
+
3
+ DynamicLinks is a flexible URL shortening Ruby gem, designed to provide various strategies for URL shortening, similar to Firebase Dynamic Links.
4
+
5
+ ## Usage
6
+
7
+ To use DynamicLinks, you need to configure the shortening strategy in an initializer or before you start shortening URLs.
8
+
9
+ ### Configuration
10
+
11
+ In your Rails initializer or similar setup code, configure DynamicLinks like this:
12
+
13
+ ```ruby
14
+ DynamicLinks.configure do |config|
15
+ config.shortening_strategy = :MD5
16
+ end
17
+ ```
18
+
19
+ ### Shortening a URL
20
+
21
+ To shorten a URL, simply call:
22
+
23
+ ```ruby
24
+ shortened_url = DynamicLinks.shorten_url("https://example.com")
25
+ ```
26
+
27
+ ## Available Shortening Strategies
28
+
29
+ DynamicLinks supports various shortening strategies. The default strategy is `MD5`, but you can choose among several others, including `NanoIdStrategy`, `RedisCounterStrategy`, `Sha256Strategy`, and more.
30
+
31
+ Depending on the strategy you choose, you may need to install additional dependencies.
32
+
33
+ ### Optional Dependencies
34
+
35
+ - For `NanoIdStrategy`, add `gem 'nanoid', '~> 2.0'` to your Gemfile.
36
+ - For `RedisCounterStrategy`, add `gem 'redis', '>= 4'` to your Gemfile.
37
+
38
+ Ensure you bundle these dependencies along with the DynamicLinks gem if you plan to use these strategies.
39
+
40
+ ## Installation
41
+
42
+ Add this line to your application's Gemfile:
43
+
44
+ ```ruby
45
+ gem "dynamic_links"
46
+ ```
47
+
48
+ And then execute:
49
+
50
+ ```bash
51
+ $ bundle
52
+ ```
53
+
54
+ Or install it yourself as:
55
+
56
+ ```bash
57
+ $ gem install dynamic_links
58
+ ```
59
+
60
+ ## Contributing
61
+
62
+ We welcome contributions to DynamicLinks! Please read the contributing guidelines to get started.
63
+
64
+ ## License
65
+
66
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/dynamic_links .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module DynamicLinks
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ class DynamicLinks::V1::ShortLinksController < ApplicationController
2
+ def create
3
+ url = params.require(:url)
4
+ # validate url
5
+ # if !url_shortener.valid_url?(url)
6
+ # render json: { error: 'invalid url' }, status: :bad_request
7
+ # return
8
+ # end
9
+
10
+ # shorten url
11
+ # save to db (not implemented yet)
12
+ render json: DynamicLinks.generate_short_url(url), status: :created
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ module DynamicLinks
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DynamicLinks
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,31 @@
1
+ module DynamicLinks
2
+ # This job generates short links in the background
3
+ # It is intended to be run periodically
4
+ # We can find available short links by querying the database with query:
5
+ # ShortenedUrl.where(available: true)
6
+ #
7
+ # To use this strategy, invoke this cli command first:
8
+ # `rails generate dynamic_links:add_kgs_migration`
9
+ class GenerateShortLinksJob < ApplicationJob
10
+ queue_as :default
11
+
12
+ # @param num_links [Integer] Number of short links to generate
13
+ def perform(num_links = 100)
14
+ num_links.times do
15
+ # TODO
16
+ # Generate a unique short code
17
+ # Store the short code in the database
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def generate_unique_short_code
24
+ loop do
25
+ # code = # TODO generate a short code using specified strategy
26
+ # break code unless ShortenedUrl.exists?(short_url: code)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,6 @@
1
+ module DynamicLinks
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module DynamicLinks
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: dynamic_links_clients
4
+ #
5
+ # id :bigint not null, primary key
6
+ # name :string not null
7
+ # api_key :string not null
8
+ # created_at :datetime not null
9
+ # updated_at :datetime not null
10
+ #
11
+ # Indexes
12
+ #
13
+ # index_dynamic_links_clients_on_api_key (api_key) UNIQUE
14
+ # index_dynamic_links_clients_on_name (name) UNIQUE
15
+ #
16
+ module DynamicLinks
17
+ class Client < ApplicationRecord
18
+ validates :name, presence: true, uniqueness: true
19
+ validates :api_key, presence: true, uniqueness: true
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: dynamic_links_shortened_urls
4
+ #
5
+ # id :bigint not null, primary key
6
+ # client_id :bigint
7
+ # url :string(2083) not null
8
+ # short_url :string(10) not null
9
+ # expires_at :datetime
10
+ # created_at :datetime not null
11
+ # updated_at :datetime not null
12
+ #
13
+ # Indexes
14
+ #
15
+ # index_dynamic_links_shortened_urls_on_client_id (client_id)
16
+ # index_dynamic_links_shortened_urls_on_short_url (short_url) UNIQUE
17
+ #
18
+ module DynamicLinks
19
+ class ShortenedUrl < ApplicationRecord
20
+ belongs_to :client, optional: true
21
+
22
+ validates :url, presence: true
23
+ validates :short_url, presence: true, uniqueness: true
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dynamic links</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "dynamic_links/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ # == Route Map
2
+ #
3
+
4
+ DynamicLinks::Engine.routes.draw do
5
+ namespace :v1 do
6
+ post "/shortLinks", to: "short_links#create", as: :short_links
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ class CreateDynamicLinksClients < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :dynamic_links_clients do |t|
4
+ t.string :name, null: false
5
+ t.string :api_key, null: false
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :dynamic_links_clients, :name, unique: true
11
+ add_index :dynamic_links_clients, :api_key, unique: true
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ class CreateDynamicLinksShortenedUrls < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :dynamic_links_shortened_urls, id: false do |t|
4
+ if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
5
+ t.bigserial :id, primary_key: true
6
+ else
7
+ t.bigint :id, primary_key: true
8
+ end
9
+
10
+ t.references :client, null: true, foreign_key: { to_table: :dynamic_links_clients }, type: :bigint
11
+ # 2083 is the maximum length of a URL according to the RFC 2616
12
+ t.string :url, null: false, limit: 2083
13
+ # 12 is the maximum length of a short URL if we use the RedisCounterStrategy
14
+ t.string :short_url, null: false, limit: DynamicLinks::ShorteningStrategies::RedisCounterStrategy::MAX_LENGTH
15
+ t.datetime :expires_at
16
+ t.timestamps
17
+ end
18
+
19
+ add_index :dynamic_links_shortened_urls, :short_url, unique: true
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module DynamicLinks
2
+ class Configuration
3
+ attr_accessor :shortening_strategy
4
+
5
+ def initialize
6
+ @shortening_strategy = :MD5 # Default strategy
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,5 @@
1
+ module DynamicLinks
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace DynamicLinks
4
+ end
5
+ end
@@ -0,0 +1,28 @@
1
+ module DynamicLinks
2
+ module ShorteningStrategies
3
+ class BaseStrategy
4
+ MIN_LENGTH = 5
5
+
6
+ BASE62_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".freeze
7
+
8
+ def shorten(url)
9
+ raise NotImplementedError, "You must implement the shorten method"
10
+ end
11
+
12
+ private
13
+
14
+ # Convert an integer into a Base62 string
15
+ def base62_encode(integer)
16
+ return '0' if integer == 0
17
+
18
+ result = ''
19
+ while integer > 0
20
+ result.prepend(BASE62_CHARS[integer % 62])
21
+ integer /= 62
22
+ end
23
+ result
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,19 @@
1
+ module DynamicLinks
2
+ module ShorteningStrategies
3
+ class CRC32Strategy < BaseStrategy
4
+ # @param url [String] The URL to shorten
5
+ # @param min_length [Integer] The minimum length of the short URL
6
+ def shorten(url, min_length: MIN_LENGTH)
7
+ # Create a CRC32 hash of the URL
8
+ hashed_url = Zlib.crc32(url).to_s(16)
9
+
10
+ # Convert the CRC32 hash into a Base62 string
11
+ short_url = base62_encode(hashed_url.to_i(16))
12
+
13
+ # Ensure the short URL is at least #{min_length} characters long
14
+ short_url.ljust(min_length, '0')
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,20 @@
1
+ module DynamicLinks
2
+ module ShorteningStrategies
3
+ class MD5Strategy < BaseStrategy
4
+ # Shortens the given URL using an MD5 hash
5
+ # @param url [String] The URL to shorten
6
+ # @param min_length [Integer] The minimum length of the short URL
7
+ def shorten(url, min_length: MIN_LENGTH)
8
+ # Create an MD5 hash of the URL
9
+ hashed_url = Digest::MD5.hexdigest(url)
10
+
11
+ # Convert a portion of the MD5 hash into a Base62 string
12
+ short_url = base62_encode(hashed_url[0...10].to_i(16))
13
+
14
+ # Ensure the short URL is at least #{min_length} characters long
15
+ short_url.ljust(min_length, '0')
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,10 @@
1
+ module DynamicLinks
2
+ module ShorteningStrategies
3
+ class MockStrategy < BaseStrategy
4
+ def shorten(url)
5
+ url
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,21 @@
1
+ module DynamicLinks
2
+ module ShorteningStrategies
3
+ # Shortens the given URL using Nano ID
4
+ # This strategy will generate a different short URL for the same given URL
5
+ class NanoIDStrategy < BaseStrategy
6
+ begin
7
+ require 'nanoid'
8
+ rescue LoadError
9
+ raise 'Missing dependency: Please add "nanoid" to your Gemfile to use NanoIdStrategy.'
10
+ end
11
+
12
+ # Shortens the given URL using Nano ID
13
+ # @param url [String] The URL to shorten (not directly used in Nano ID strategy)
14
+ # @param size [Integer] The size (length) of the generated Nano ID
15
+ def shorten(url, size: MIN_LENGTH)
16
+ ::Nanoid.generate(size: size)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,31 @@
1
+
2
+ module DynamicLinks
3
+ module ShorteningStrategies
4
+ class RedisCounterStrategy < BaseStrategy
5
+ begin
6
+ require 'redis'
7
+ rescue LoadError
8
+ raise 'Missing dependency: Please add "redis" to your Gemfile to use RedisCounterStrategy.'
9
+ end
10
+
11
+ MIN_LENGTH = 12
12
+ REDIS_COUNTER_KEY = "dynamic_links:counter".freeze
13
+
14
+ def initialize
15
+ # TODO: use pool of connections
16
+ @redis = Redis.new
17
+ end
18
+
19
+ # Shortens the given URL using a Redis counter
20
+ # @param url [String] The URL to shorten
21
+ # @return [String] The shortened URL, 12 characters long
22
+ def shorten(url, min_length: MIN_LENGTH)
23
+ counter = @redis.incr(REDIS_COUNTER_KEY)
24
+
25
+ short_url = base62_encode("#{counter}#{url.hash.abs}".to_i)
26
+ short_url.ljust(min_length, '0')
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,20 @@
1
+ module DynamicLinks
2
+ module ShorteningStrategies
3
+ class SHA256Strategy < BaseStrategy
4
+ # @param url [String] The URL to shorten
5
+ # @param min_length [Integer] The minimum length of the short URL
6
+ # we use this parameter to increase the length of the short URL
7
+ # in order to avoid collisions
8
+ def shorten(url, min_length: MIN_LENGTH)
9
+ # Create a hash of the URL
10
+ hashed_url = Digest::SHA256.hexdigest(url)
11
+
12
+ # Convert the first few characters of the hash into a Base62 string
13
+ short_url = base62_encode(hashed_url[0...10].to_i(16))
14
+
15
+ # Ensure the short URL is at least #{min_length} characters
16
+ short_url.ljust(min_length, '0')
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ module DynamicLinks
2
+ class StrategyFactory
3
+ def self.get_strategy(strategy_name)
4
+ case strategy_name
5
+ when :md5
6
+ ShorteningStrategies::MD5Strategy.new
7
+ when :sha256
8
+ ShorteningStrategies::SHA256Strategy.new
9
+ when :crc32
10
+ ShorteningStrategies::CRC32Strategy.new
11
+ when :nano_id
12
+ ShorteningStrategies::NanoIdStrategy.new
13
+ when :redis_counter
14
+ ShorteningStrategies::RedisCounterStrategy.new
15
+ when :mock
16
+ ShorteningStrategies::MockStrategy.new
17
+ else
18
+ raise "Unknown strategy: #{strategy_name}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,3 @@
1
+ module DynamicLinks
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,53 @@
1
+ require "dynamic_links/version"
2
+ require "dynamic_links/engine"
3
+ require "dynamic_links/strategy_factory"
4
+ require "dynamic_links/shortening_strategies/base_strategy"
5
+ require "dynamic_links/shortening_strategies/sha256_strategy"
6
+ require "dynamic_links/shortening_strategies/md5_strategy"
7
+ require "dynamic_links/shortening_strategies/crc32_strategy"
8
+ require "dynamic_links/shortening_strategies/nano_id_strategy"
9
+ require "dynamic_links/shortening_strategies/redis_counter_strategy"
10
+ require "dynamic_links/shortening_strategies/mock_strategy"
11
+ require "dynamic_links/configuration"
12
+
13
+ module DynamicLinks
14
+ class << self
15
+ attr_writer :configuration
16
+
17
+ def configuration
18
+ @configuration ||= Configuration.new
19
+ end
20
+
21
+ def configure
22
+ yield(configuration)
23
+ end
24
+ end
25
+
26
+ def self.shorten_url(url)
27
+ strategy_key = configuration.shortening_strategy
28
+
29
+ begin
30
+ strategy = StrategyFactory.get_strategy(strategy_key)
31
+ rescue RuntimeError => e
32
+ # This will catch the 'Unknown strategy' error from the factory
33
+ raise "Invalid shortening strategy: #{strategy_key}. Error: #{e.message}"
34
+ rescue ArgumentError
35
+ raise "#{strategy_key} strategy needs to be initialized with arguments"
36
+ rescue => e
37
+ raise "Unexpected error while initializing the strategy: #{e.message}"
38
+ end
39
+
40
+ strategy.shorten(url)
41
+ end
42
+
43
+ # mimic Firebase Dynamic Links API
44
+ def self.generate_short_url(original_url)
45
+ short_link = shorten_url(original_url)
46
+
47
+ {
48
+ shortLink: short_link,
49
+ previewLink: "#{short_link}?preview=true",
50
+ warning: []
51
+ }
52
+ end
53
+ end
@@ -0,0 +1,16 @@
1
+ module DynamicLinks
2
+ module Generators
3
+ class AddKgsMigrationGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('templates', __dir__)
5
+
6
+ def create_migration_file
7
+ timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S")
8
+ migration_filename = "#{timestamp}_add_available_to_shortened_urls.rb"
9
+ migration_template = File.read(File.join(self.class.source_root, "migration_template.rb"))
10
+
11
+ create_file "db/migrate/#{migration_filename}", migration_template
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,6 @@
1
+ class AddAvailableToShortenedUrls < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :dynamic_links_shortened_urls, :available, :boolean, null: false, default: true
4
+ add_index :dynamic_links_shortened_urls, :available
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :dynamic_links do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dynamic_links
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Saiqul Haq
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-01-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nanoid
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: annotate
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: dotenv-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Rails engine to shorten any URL with custom domain.
84
+ email:
85
+ - saiqulhaq@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - README.md
91
+ - Rakefile
92
+ - app/assets/config/dynamic_links_manifest.js
93
+ - app/assets/stylesheets/dynamic_links/application.css
94
+ - app/controllers/dynamic_links/application_controller.rb
95
+ - app/controllers/dynamic_links/v1/short_links_controller.rb
96
+ - app/helpers/dynamic_links/application_helper.rb
97
+ - app/jobs/dynamic_links/application_job.rb
98
+ - app/jobs/dynamic_links/generate_short_links_job.rb
99
+ - app/mailers/dynamic_links/application_mailer.rb
100
+ - app/models/dynamic_links/application_record.rb
101
+ - app/models/dynamic_links/client.rb
102
+ - app/models/dynamic_links/shortened_url.rb
103
+ - app/views/layouts/dynamic_links/application.html.erb
104
+ - config/routes.rb
105
+ - db/migrate/20231228165744_create_dynamic_links_clients.rb
106
+ - db/migrate/20231228175142_create_dynamic_links_shortened_urls.rb
107
+ - lib/dynamic_links.rb
108
+ - lib/dynamic_links/configuration.rb
109
+ - lib/dynamic_links/engine.rb
110
+ - lib/dynamic_links/shortening_strategies/base_strategy.rb
111
+ - lib/dynamic_links/shortening_strategies/crc32_strategy.rb
112
+ - lib/dynamic_links/shortening_strategies/md5_strategy.rb
113
+ - lib/dynamic_links/shortening_strategies/mock_strategy.rb
114
+ - lib/dynamic_links/shortening_strategies/nano_id_strategy.rb
115
+ - lib/dynamic_links/shortening_strategies/redis_counter_strategy.rb
116
+ - lib/dynamic_links/shortening_strategies/sha256_strategy.rb
117
+ - lib/dynamic_links/strategy_factory.rb
118
+ - lib/dynamic_links/version.rb
119
+ - lib/generators/dynamic_links/add_kgs_migration_generator.rb
120
+ - lib/generators/dynamic_links/templates/migration_template.rb
121
+ - lib/tasks/dynamic_links_tasks.rake
122
+ homepage: https://saiqulhaq.id/dynamic_links
123
+ licenses: []
124
+ metadata:
125
+ homepage_uri: https://saiqulhaq.id/dynamic_links
126
+ source_code_uri: https://github.com/saiqulhaq/dynamic_links
127
+ changelog_uri: https://github.com/saiqulhaq/dynamic_links/blob/master/CHANGELOG.md
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubygems_version: 3.1.2
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Alternative to Firebase Dynamic Links feature
147
+ test_files: []