izolenta 0.0.3 → 0.0.6
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/.rubocop.yml +92 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +28 -2
- data/README.md +12 -0
- data/Rakefile +3 -1
- data/docker-compose.yml +8 -0
- data/izolenta.gemspec +11 -8
- data/lib/izolenta/active_record_migration.rb +71 -56
- data/lib/izolenta/version.rb +3 -1
- data/lib/izolenta.rb +3 -1
- data/ruby3.Dockerfile +20 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd520ce5cefeee28f6985c56bc36b29f102dfdb5972ee736d6cabd11928139b9
|
4
|
+
data.tar.gz: 8e3e5acc0b8d853e9f78a9a8b1bc25e3e08836c506e0787fdb465420700f81fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d63396b28549ecde16b8e810c3c667c2a0245ee6fdce41cc9f1239abd5ebbad50e9b22a71780bf3b73ee7911bedd865e2d4f9315af6541ca226d5891b57f5dde
|
7
|
+
data.tar.gz: 8713a4d8039f843fe4d5eb9487a1dcf54146e83bc09564383a1673407034de28b3e1d6469b349dcf44ec23ca2f9b4a77b6d5d0dff23cc3828d87bd30fe25c9c6
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
inherit_gem:
|
2
|
+
rubocop-shopify: rubocop.yml
|
3
|
+
#
|
4
|
+
#Style/SingleLineMethods:
|
5
|
+
# Description: 'Avoid single-line methods.'
|
6
|
+
# StyleGuide: '#no-single-line-methods'
|
7
|
+
# Enabled: false
|
8
|
+
# VersionAdded: '0.9'
|
9
|
+
# VersionChanged: '1.8'
|
10
|
+
# AllowIfMethodIsEmpty: true
|
11
|
+
#
|
12
|
+
#Style/AsciiComments:
|
13
|
+
# Description: 'Use only ascii symbols in comments.'
|
14
|
+
# StyleGuide: '#english-comments'
|
15
|
+
# Enabled: false
|
16
|
+
# VersionAdded: '0.9'
|
17
|
+
# VersionChanged: '1.21'
|
18
|
+
# AllowedChars:
|
19
|
+
# - ©
|
20
|
+
#
|
21
|
+
#Layout/LineLength:
|
22
|
+
# Description: 'Checks that line length does not exceed the configured limit.'
|
23
|
+
# StyleGuide: '#max-line-length'
|
24
|
+
# Enabled: true
|
25
|
+
# VersionAdded: '0.25'
|
26
|
+
# VersionChanged: '1.4'
|
27
|
+
# Max: 120
|
28
|
+
# # To make it possible to copy or click on URIs in the code, we allow lines
|
29
|
+
# # containing a URI to be longer than Max.
|
30
|
+
# AllowHeredoc: true
|
31
|
+
# AllowURI: true
|
32
|
+
# URISchemes:
|
33
|
+
# - http
|
34
|
+
# - https
|
35
|
+
# # The IgnoreCopDirectives option causes the LineLength rule to ignore cop
|
36
|
+
# # directives like '# rubocop: enable ...' when calculating a line's length.
|
37
|
+
# IgnoreCopDirectives: true
|
38
|
+
# # The AllowedPatterns option is a list of !ruby/regexp and/or string
|
39
|
+
# # elements. Strings will be converted to Regexp objects. A line that matches
|
40
|
+
# # any regular expression listed in this option will be ignored by LineLength.
|
41
|
+
# AllowedPatterns: []
|
42
|
+
# IgnoredPatterns: [] # deprecated
|
43
|
+
# Exclude:
|
44
|
+
# - "./test/**/**/*"
|
45
|
+
#
|
46
|
+
#Metrics/ClassLength:
|
47
|
+
# Description: 'Avoid classes longer than 100 lines of code.'
|
48
|
+
# Enabled: false
|
49
|
+
# VersionAdded: '0.25'
|
50
|
+
# VersionChanged: '0.87'
|
51
|
+
# CountComments: false # count full line comments?
|
52
|
+
# Max: 100
|
53
|
+
# CountAsOne: []
|
54
|
+
#
|
55
|
+
#Lint/MissingCopEnableDirective:
|
56
|
+
# Description: 'Checks for a `# rubocop:enable` after `# rubocop:disable`.'
|
57
|
+
# Enabled: true
|
58
|
+
# VersionAdded: '0.52'
|
59
|
+
# # Maximum number of consecutive lines the cop can be disabled for.
|
60
|
+
# # 0 allows only single-line disables
|
61
|
+
# # 1 would mean the maximum allowed is the following:
|
62
|
+
# # # rubocop:disable SomeCop
|
63
|
+
# # a = 1
|
64
|
+
# # # rubocop:enable SomeCop
|
65
|
+
# # .inf for any size
|
66
|
+
# MaximumRangeSize: .inf
|
67
|
+
#
|
68
|
+
#Style/MethodCallWithArgsParentheses:
|
69
|
+
# Enabled: true
|
70
|
+
# IgnoredMethods:
|
71
|
+
# - require
|
72
|
+
# - require_relative
|
73
|
+
# - require_dependency
|
74
|
+
# - yield
|
75
|
+
# - raise
|
76
|
+
# - puts
|
77
|
+
# Exclude:
|
78
|
+
# - "/**/Gemfile"
|
79
|
+
# - "./db/**/*"
|
80
|
+
#
|
81
|
+
#Layout/EmptyLinesAroundBlockBody:
|
82
|
+
# # its more documentation than code, so it should be readable and
|
83
|
+
# # there are huge amount of multiline description, looks nasty without spaces
|
84
|
+
# Exclude:
|
85
|
+
# - "./app_doc/**/*"
|
86
|
+
#
|
87
|
+
#Style/ClassAndModuleChildren:
|
88
|
+
# Enabled: false
|
89
|
+
#
|
90
|
+
#Lint/UnderscorePrefixedVariableName:
|
91
|
+
# Exclude:
|
92
|
+
# - "./test/**/**/*"
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
|
+
#0.0.6
|
2
|
+
- new ruby 3 image for ruby 3 testing
|
3
|
+
- fix get_new_column_type incompatibility with ruby
|
4
|
+
|
5
|
+
#0.0.5
|
6
|
+
- rubocop-shopify added to dev dependencies
|
7
|
+
- fixed ruby 3.0 incompatibility in delegate_uniqueness, now gem could be used with ruby 3+
|
8
|
+
|
9
|
+
#0.0.4
|
10
|
+
- removed 'OR REPLACE' in trigger definition, lowering Postgres version constraint
|
11
|
+
- trigger_condition added ( could replace partial uniq index )
|
12
|
+
|
1
13
|
#0.0.3
|
2
14
|
- wrapper_function options added, you can define function to convert to uniquely sortable types, for instance array to string
|
15
|
+
- moved all helper functions to internal module, just to keep things clear on the migrations
|
3
16
|
|
4
17
|
#0.0.2
|
5
18
|
- delegate_uniqueness helper is available as a migration method
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
izolenta (0.0.
|
4
|
+
izolenta (0.0.5)
|
5
5
|
pg
|
6
6
|
|
7
7
|
GEM
|
@@ -18,18 +18,41 @@ GEM
|
|
18
18
|
minitest (>= 5.1)
|
19
19
|
tzinfo (~> 2.0)
|
20
20
|
zeitwerk (~> 2.3)
|
21
|
+
ast (2.4.2)
|
21
22
|
byebug (11.1.3)
|
22
23
|
coderay (1.1.3)
|
23
24
|
concurrent-ruby (1.1.9)
|
24
25
|
i18n (1.8.11)
|
25
26
|
concurrent-ruby (~> 1.0)
|
27
|
+
json (2.6.2)
|
26
28
|
method_source (1.0.0)
|
27
29
|
minitest (5.14.4)
|
28
|
-
|
30
|
+
parallel (1.22.1)
|
31
|
+
parser (3.1.2.0)
|
32
|
+
ast (~> 2.4.1)
|
33
|
+
pg (1.4.1)
|
29
34
|
pry (0.13.1)
|
30
35
|
coderay (~> 1.1)
|
31
36
|
method_source (~> 1.0)
|
37
|
+
rainbow (3.1.1)
|
32
38
|
rake (12.3.3)
|
39
|
+
regexp_parser (2.5.0)
|
40
|
+
rexml (3.2.5)
|
41
|
+
rubocop (1.31.2)
|
42
|
+
json (~> 2.3)
|
43
|
+
parallel (~> 1.10)
|
44
|
+
parser (>= 3.1.0.0)
|
45
|
+
rainbow (>= 2.2.2, < 4.0)
|
46
|
+
regexp_parser (>= 1.8, < 3.0)
|
47
|
+
rexml (>= 3.2.5, < 4.0)
|
48
|
+
rubocop-ast (>= 1.18.0, < 2.0)
|
49
|
+
ruby-progressbar (~> 1.7)
|
50
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
51
|
+
rubocop-ast (1.18.0)
|
52
|
+
parser (>= 3.1.1.0)
|
53
|
+
rubocop-shopify (2.8.0)
|
54
|
+
rubocop (~> 1.31)
|
55
|
+
ruby-progressbar (1.11.0)
|
33
56
|
ruby_jard (0.3.1)
|
34
57
|
byebug (>= 9.1, < 12.0)
|
35
58
|
pry (~> 0.13.0)
|
@@ -37,6 +60,7 @@ GEM
|
|
37
60
|
tty-screen (0.8.1)
|
38
61
|
tzinfo (2.0.4)
|
39
62
|
concurrent-ruby (~> 1.0)
|
63
|
+
unicode-display_width (2.2.0)
|
40
64
|
zeitwerk (2.5.1)
|
41
65
|
|
42
66
|
PLATFORMS
|
@@ -47,6 +71,8 @@ DEPENDENCIES
|
|
47
71
|
izolenta!
|
48
72
|
minitest (~> 5.0)
|
49
73
|
rake (~> 12.0)
|
74
|
+
rubocop
|
75
|
+
rubocop-shopify
|
50
76
|
ruby_jard
|
51
77
|
|
52
78
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -46,6 +46,15 @@ class WithWrapperFunctionMigration < ActiveRecord::Migration[5.0]
|
|
46
46
|
delegate_uniqueness( :your_table_name, :column_name, wrapper_function: 'type_conversion_function' )
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
|
51
|
+
class WithWrapperFunctionMigration < ActiveRecord::Migration[5.0]
|
52
|
+
# apply trigger condition for partial uniqueness
|
53
|
+
def change
|
54
|
+
delegate_uniqueness( :your_table_name, :column_name, trigger_condition: 'NEW.type IS NOT NULL' )
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
49
58
|
```
|
50
59
|
|
51
60
|
## Development
|
@@ -55,6 +64,9 @@ docker-compose build
|
|
55
64
|
|
56
65
|
docker-compose run test /bin/bash
|
57
66
|
> service postgresql start && rake test
|
67
|
+
|
68
|
+
docker-compose run test3 /bin/bash
|
69
|
+
> service postgresql start && rake test
|
58
70
|
```
|
59
71
|
|
60
72
|
## Future Features
|
data/Rakefile
CHANGED
data/docker-compose.yml
CHANGED
data/izolenta.gemspec
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/izolenta/version"
|
2
4
|
|
3
5
|
Gem::Specification.new do |spec|
|
4
6
|
spec.name = "izolenta"
|
@@ -6,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
6
8
|
spec.authors = ["alekseyl"]
|
7
9
|
spec.email = ["leshchuk@gmail.com"]
|
8
10
|
|
9
|
-
spec.summary =
|
10
|
-
spec.description =
|
11
|
+
spec.summary = "Migration helpers for delegated uniqueness in Postgres"
|
12
|
+
spec.description = "Migration helpers for delegated uniqueness in Postgres"
|
11
13
|
spec.homepage = "https://github.com/alekseyl/izolenta"
|
12
14
|
spec.license = "MIT"
|
13
15
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
@@ -20,14 +22,15 @@ Gem::Specification.new do |spec|
|
|
20
22
|
|
21
23
|
# Specify which files should be added to the gem when it is released.
|
22
24
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
-
spec.files
|
24
|
-
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
26
|
+
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
27
|
end
|
26
28
|
spec.bindir = "exe"
|
27
29
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
30
|
spec.require_paths = ["lib"]
|
29
31
|
|
30
|
-
spec.add_dependency
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
32
|
+
spec.add_dependency("pg")
|
33
|
+
spec.add_development_dependency("activerecord", ">= 5")
|
34
|
+
spec.add_development_dependency("rubocop-shopify")
|
35
|
+
spec.add_development_dependency("ruby_jard")
|
33
36
|
end
|
@@ -1,71 +1,86 @@
|
|
1
|
-
|
2
|
-
# options:
|
3
|
-
# wrapper_function: 'some_func' # some_func should be defined prior
|
4
|
-
def delegate_uniqueness(origin_table, column, options = {})
|
5
|
-
helper_table_name = "#{column}_#{origin_table}_uniqs"
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
if defined? ActiveRecord
|
4
|
+
module Izolenta
|
5
|
+
module ActiveRecordMigration
|
6
|
+
# options:
|
7
|
+
# wrapper_function: 'some_func' # some_func should be defined prior
|
8
|
+
def delegate_uniqueness(origin_table, column, **options)
|
9
|
+
helper_table_name = "#{column}_#{origin_table}_uniqs"
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
reversible do |dir|
|
12
|
+
dir.up do
|
13
|
+
Helpers.create_helper_table(helper_table_name, column,
|
14
|
+
Helpers.get_new_column_type(origin_table, column, **options))
|
15
|
+
add_index(helper_table_name, column, unique: true)
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
Helpers.drop_sync_trigger( origin_table, column )
|
18
|
-
}
|
19
|
-
end
|
20
|
-
end
|
17
|
+
Helpers.create_sync_trigger(origin_table, column, helper_table_name, options)
|
18
|
+
end
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
dir.down do
|
21
|
+
drop_table(helper_table_name)
|
22
|
+
Helpers.drop_sync_trigger(origin_table, column)
|
23
|
+
end
|
24
|
+
end
|
26
25
|
end
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
BEGIN
|
35
|
-
INSERT INTO #{helper_table_name} VALUES ( #{insert_value} );
|
36
|
-
RETURN NEW;
|
37
|
-
END $$ LANGUAGE plpgSQL;
|
38
|
-
|
39
|
-
CREATE OR REPLACE TRIGGER #{trg_name} BEFORE INSERT ON #{table} FOR EACH ROW
|
40
|
-
EXECUTE FUNCTION #{trg_name}();
|
41
|
-
SYNC_TRIGGER
|
42
|
-
end
|
27
|
+
# helpers na
|
28
|
+
module Helpers
|
29
|
+
class << self
|
30
|
+
def create_helper_table(helper_table, column_name, column_type)
|
31
|
+
ActiveRecord::Base.connection.execute("CREATE TABLE #{helper_table} ( #{column_name} #{column_type} );")
|
32
|
+
end
|
43
33
|
|
44
|
-
|
45
|
-
|
34
|
+
def create_sync_trigger(table, column_name, helper_table_name, options)
|
35
|
+
trg_name = "#{table}_#{column_name}_trg"
|
36
|
+
insert_value = if options[:wrapper_function]
|
37
|
+
"#{options[:wrapper_function]}(NEW.#{column_name})"
|
38
|
+
else
|
39
|
+
"NEW.#{column_name}"
|
40
|
+
end
|
46
41
|
|
47
|
-
|
48
|
-
DROP TRIGGER IF EXISTS #{trg_name} ON #{table};
|
49
|
-
SYNC_TRIGGER
|
50
|
-
end
|
42
|
+
trigger_condition = "WHEN( #{options[:trigger_condition]} )" if options[:trigger_condition]
|
51
43
|
|
52
|
-
|
53
|
-
|
54
|
-
|
44
|
+
ActiveRecord::Base.connection.execute(<<~SYNC_TRIGGER)
|
45
|
+
CREATE OR REPLACE FUNCTION #{trg_name}() RETURNS trigger AS $$
|
46
|
+
BEGIN#{" "}
|
47
|
+
INSERT INTO #{helper_table_name} VALUES ( #{insert_value} );
|
48
|
+
RETURN NEW;
|
49
|
+
END $$ LANGUAGE plpgSQL;
|
55
50
|
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
CREATE TRIGGER #{trg_name} BEFORE INSERT ON #{table}#{" "}
|
52
|
+
FOR EACH ROW
|
53
|
+
#{trigger_condition}
|
54
|
+
EXECUTE FUNCTION #{trg_name}();
|
55
|
+
SYNC_TRIGGER
|
56
|
+
end
|
59
57
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
58
|
+
def drop_sync_trigger(table, column_name)
|
59
|
+
trg_name = "#{table}_#{column_name}_trg"
|
60
|
+
|
61
|
+
ActiveRecord::Base.connection.execute(<<~SYNC_TRIGGER)
|
62
|
+
DROP TRIGGER IF EXISTS #{trg_name} ON #{table};
|
63
|
+
SYNC_TRIGGER
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_new_column_type(origin_table, column, wrapper_function: nil, **)
|
67
|
+
wrapper_function ? get_function_type(wrapper_function) : get_column_type(origin_table, column)
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_column_type(origin_table, column)
|
71
|
+
ActiveRecord::Base.connection.schema_cache.columns_hash(origin_table.to_s)[column.to_s]&.sql_type
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_function_type(wrapper_function)
|
75
|
+
ActiveRecord::Base
|
76
|
+
.connection
|
77
|
+
.execute("SELECT typname FROM pg_type WHERE oid=(SELECT prorettype FROM pg_proc WHERE proname ='#{wrapper_function}')") # rubocop:disable Layout/LineLength
|
78
|
+
.first["typname"]
|
79
|
+
end
|
80
|
+
end
|
65
81
|
end
|
66
82
|
end
|
67
83
|
end
|
84
|
+
end
|
68
85
|
|
69
|
-
|
70
|
-
|
71
|
-
ActiveRecord::Migration.include(Izolenta::ActiveRecordMigration) if defined? ActiveRecord
|
86
|
+
ActiveRecord::Migration.include(Izolenta::ActiveRecordMigration) if defined? ActiveRecord
|
data/lib/izolenta/version.rb
CHANGED
data/lib/izolenta.rb
CHANGED
data/ruby3.Dockerfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
FROM ruby:3-bullseye
|
2
|
+
|
3
|
+
WORKDIR /app
|
4
|
+
RUN apt-get update && apt-get -y install lsb-release
|
5
|
+
#
|
6
|
+
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
|
7
|
+
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \
|
8
|
+
apt-get update && apt-get -y install postgresql postgresql-client-12
|
9
|
+
|
10
|
+
RUN sh -c 'echo "local all all trust" > /etc/postgresql/14/main/pg_hba.conf' && \
|
11
|
+
service postgresql start && \
|
12
|
+
psql -U postgres -c 'CREATE DATABASE "izolenta-test"'
|
13
|
+
|
14
|
+
RUN gem install bundler
|
15
|
+
|
16
|
+
COPY lib/izolenta/version.rb /app/lib/izolenta/version.rb
|
17
|
+
COPY izolenta.gemspec /app/
|
18
|
+
COPY Gemfil* /app/
|
19
|
+
#
|
20
|
+
RUN bundle install
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: izolenta
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- alekseyl
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop-shopify
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: ruby_jard
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +74,7 @@ extensions: []
|
|
60
74
|
extra_rdoc_files: []
|
61
75
|
files:
|
62
76
|
- ".gitignore"
|
77
|
+
- ".rubocop.yml"
|
63
78
|
- ".ruby-gemset"
|
64
79
|
- ".ruby-version"
|
65
80
|
- ".travis.yml"
|
@@ -77,6 +92,7 @@ files:
|
|
77
92
|
- lib/izolenta.rb
|
78
93
|
- lib/izolenta/active_record_migration.rb
|
79
94
|
- lib/izolenta/version.rb
|
95
|
+
- ruby3.Dockerfile
|
80
96
|
homepage: https://github.com/alekseyl/izolenta
|
81
97
|
licenses:
|
82
98
|
- MIT
|