activerecord-model_inheritance 1.0.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 (26) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +451 -0
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE +21 -0
  6. data/README.md +255 -0
  7. data/Rakefile +7 -0
  8. data/lib/active_record/model_inheritance/error.rb +5 -0
  9. data/lib/active_record/model_inheritance/model.rb +169 -0
  10. data/lib/active_record/model_inheritance/version.rb +5 -0
  11. data/lib/active_record/model_inheritance/view_definition.rb +112 -0
  12. data/lib/active_record/model_inheritance.rb +57 -0
  13. data/lib/activerecord/model_inheritance.rb +1 -0
  14. data/lib/generators/active_record/model_inheritance/generators.rb +6 -0
  15. data/lib/generators/active_record/model_inheritance/model/model_generator.rb +75 -0
  16. data/lib/generators/active_record/model_inheritance/model/templates/definition.erb +1 -0
  17. data/lib/generators/active_record/model_inheritance/model/templates/model.erb +2 -0
  18. data/lib/generators/active_record/model_inheritance/model/templates/model_config.erb +3 -0
  19. data/lib/generators/active_record/model_inheritance/view/templates/create_migration.erb +13 -0
  20. data/lib/generators/active_record/model_inheritance/view/templates/update_migration.erb +5 -0
  21. data/lib/generators/active_record/model_inheritance/view/view_generator.rb +121 -0
  22. data/sig/active_record/model_inheritance/generators/model_generator.rbs +23 -0
  23. data/sig/active_record/model_inheritance/generators/view_generator.rbs +45 -0
  24. data/sig/active_record/model_inheritance/version.rbs +5 -0
  25. data/sig/active_record/model_inheritance/view_definition.rbs +20 -0
  26. metadata +127 -0
@@ -0,0 +1,75 @@
1
+ require 'rails/generators'
2
+ require 'active_record/model_inheritance'
3
+
4
+ module ActiveRecord
5
+ module ModelInheritance
6
+ module Generators
7
+ class ModelGenerator < Rails::Generators::NamedBase
8
+ source_root File.expand_path('templates', __dir__)
9
+
10
+ desc 'Create derived model and definition files'
11
+
12
+ argument :derives_from, type: :string, optional: false
13
+
14
+ class_option :only_definition,
15
+ type: :boolean,
16
+ required: false,
17
+ default: false,
18
+ desc: 'Whether or not to generate only the definition file'
19
+
20
+ def generate_model
21
+ return if skip_generate_model?
22
+
23
+ if rails_application?
24
+ invoke 'model',
25
+ [file_path.singularize],
26
+ options.merge(
27
+ fixture_replacement: false,
28
+ migration: false
29
+ )
30
+ else
31
+ template 'model.erb', ModelInheritance.models_path.join("#{file_path.singularize}.rb")
32
+ end
33
+ end
34
+
35
+ def inject_configuration_to_model
36
+ return if skip_generate_model?
37
+
38
+ inject_into_class ModelInheritance.models_path.join("#{file_path.singularize}.rb"), class_name do
39
+ evaluate_template 'model_config.erb'
40
+ end
41
+ end
42
+
43
+ def create_definition_file
44
+ template 'definition.erb', ModelInheritance.definitions_path.join("#{table_name}.rb")
45
+ end
46
+
47
+ no_tasks do
48
+ def evaluate_template source
49
+ source = File.expand_path find_in_source_paths(source.to_s)
50
+
51
+ erb = ERB.new(
52
+ File.read(source),
53
+ trim_mode: '-',
54
+ eoutvar: '@output_buffer'
55
+ )
56
+
57
+ erb.result binding
58
+ end
59
+
60
+ def rails_application?
61
+ defined?(Rails.application) && Rails.application.present?
62
+ end
63
+
64
+ def skip_generate_model?
65
+ options[:only_definition]
66
+ end
67
+
68
+ def formatted_base_name
69
+ "::#{derives_from.camelize}"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1 @@
1
+ ActiveRecord::ModelInheritance::ViewDefinition.define_derived_view <%= name %>
@@ -0,0 +1,2 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+ end
@@ -0,0 +1,3 @@
1
+ include ActiveRecord::ModelInheritance::Model
2
+
3
+ derives_from <%= formatted_base_name %>
@@ -0,0 +1,13 @@
1
+ class <%= migration_class_name %> < <%= activerecord_migration_class %>
2
+ def change
3
+ create_table <%= formatted_inner_table_name %> do |t|
4
+ # add your derived model extra fields here
5
+
6
+ t.references <%= formatted_base_name %>, foreign_key: true
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ create_view <%= formatted_table_name %>
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class <%= migration_class_name %> < <%= activerecord_migration_class %>
2
+ def change
3
+ update_view <%= formatted_table_name %>, version: <%= next_version %>, revert_to_version: <%= current_version %>
4
+ end
5
+ end
@@ -0,0 +1,121 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/active_record'
3
+ require 'active_record/model_inheritance'
4
+ require 'active_record/model_inheritance/view_definition'
5
+
6
+ module ActiveRecord
7
+ module ModelInheritance
8
+ module Generators
9
+ class ViewGenerator < Rails::Generators::NamedBase
10
+ include Rails::Generators::Migration
11
+
12
+ desc 'Generate SQL view definition and create initial/update migration'
13
+
14
+ source_root File.expand_path('templates', __dir__)
15
+
16
+ class_option :skip_migration,
17
+ type: :boolean,
18
+ required: false,
19
+ default: false,
20
+ desc: 'Whether or not to generate a migration file'
21
+
22
+ def create_view_file
23
+ create_file ModelInheritance
24
+ .views_path
25
+ .join("#{table_name}_v#{formatted_next_version}.sql"),
26
+ view_definition.to_sql
27
+ end
28
+
29
+ def create_migration_file
30
+ return if skip_generate_migration?
31
+
32
+ if creating?
33
+ migration_template(
34
+ 'create_migration.erb',
35
+ ModelInheritance.migrations_path.join("create_#{table_name}.rb")
36
+ )
37
+ else
38
+ migration_template(
39
+ 'update_migration.erb',
40
+ ModelInheritance.migrations_path.join("update_#{table_name}_to_version_#{formatted_next_version}.rb")
41
+ )
42
+ end
43
+ end
44
+
45
+ def self.next_migration_number dir
46
+ ::ActiveRecord::Generators::Base.next_migration_number dir
47
+ end
48
+
49
+ no_tasks do
50
+ def current_version
51
+ @current_version ||= ModelInheritance
52
+ .views_path
53
+ .glob("#{table_name}_v*.sql")
54
+ .last
55
+ .then { |last_version_file| last_version_file&.basename&.to_s }
56
+ .then do |last_version_name|
57
+ version_regex
58
+ .match(last_version_name)
59
+ .try(:[], :version)
60
+ .to_i
61
+ end
62
+ end
63
+
64
+ def next_version
65
+ @next_version ||= current_version.next
66
+ end
67
+
68
+ def formatted_next_version
69
+ next_version
70
+ .to_s
71
+ .rjust(2, '0')
72
+ end
73
+
74
+ def creating?
75
+ current_version.zero?
76
+ end
77
+
78
+ def skip_generate_migration?
79
+ options[:skip_migration]
80
+ end
81
+
82
+ def version_regex
83
+ %r{\A#{table_name}_v(?<version>\d+)\.sql\z}
84
+ end
85
+
86
+ def formatted_class_name
87
+ class_name.tr('.:', '').pluralize
88
+ end
89
+
90
+ def migration_class_name
91
+ if creating?
92
+ "Create#{formatted_class_name}"
93
+ else
94
+ "Update#{formatted_class_name}ToVersion#{next_version}"
95
+ end
96
+ end
97
+
98
+ def activerecord_migration_class
99
+ "ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
100
+ end
101
+
102
+ def formatted_inner_table_name
103
+ ":#{view_definition.model_class.model_inheritance_inner_model.table_name}"
104
+ end
105
+
106
+ def formatted_base_name
107
+ ":#{view_definition.model_class.model_inheritance_base_model.model_name.singular}"
108
+ end
109
+
110
+ def formatted_table_name
111
+ ":#{table_name}"
112
+ end
113
+
114
+ def view_definition
115
+ @view_definition ||= ViewDefinition.from_name table_name
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveRecord
2
+ module ModelInheritance
3
+ module Generators
4
+ class ModelGenerator < Rails::Generators::NamedBase
5
+ def generate_model: () -> void
6
+
7
+ def inject_configuration_to_model: () -> void
8
+
9
+ def create_definition_file: () -> void
10
+
11
+ def evaluate_template: (String source) -> String
12
+
13
+ def rails_application?: () -> bool
14
+
15
+ def skip_generate_model?: () -> bool
16
+
17
+ def formatted_base_name: () -> String
18
+
19
+ def formatted_base_reference: () -> String
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ module ActiveRecord
2
+ module ModelInheritance
3
+ module Generators
4
+ class ViewGenerator < Rails::Generators::NamedBase
5
+ include Rails::Generators::Migration
6
+
7
+ @current_version: Integer
8
+ @next_version: Integer
9
+ @view_definition: ViewDefinition
10
+
11
+ def create_view_file: () -> void
12
+
13
+ def create_migration_file: () -> void
14
+
15
+ def self.next_migration_number: (untyped dir) -> untyped
16
+
17
+ def current_version: () -> Integer
18
+
19
+ def next_version: () -> Integer
20
+
21
+ def formatted_next_version: () -> String
22
+
23
+ def creating?: () -> bool
24
+
25
+ def skip_generate_migration?: () -> bool
26
+
27
+ def version_regex: () -> Regexp
28
+
29
+ def formatted_class_name: () -> String
30
+
31
+ def migration_class_name: () -> String
32
+
33
+ def activerecord_migration_class: () -> String
34
+
35
+ def formatted_inner_table_name: () -> String
36
+
37
+ def formatted_base_name: () -> String
38
+
39
+ def formatted_table_name: () -> String
40
+
41
+ def view_definition: () -> ViewDefinition
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveRecord
2
+ module ModelInheritance
3
+ VERSION: String
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ module ActiveRecord
2
+ module ModelInheritance
3
+ class ViewDefinition
4
+ def initialize: (Class model_class, untyped definition) -> void
5
+
6
+ def self.define_derived_view: (Class model_class) -> ViewDefinition
7
+
8
+ def self.from_model: (Class model_class) -> ViewDefinition
9
+
10
+ def self.from_name: (String name) -> ViewDefinition
11
+
12
+ attr_reader definition: untyped
13
+ attr_reader model_class: Class
14
+
15
+ def attributes_mapping: -> {base: Array[Symbol], inner: Array[Symbol]}
16
+
17
+ def to_sql: -> String
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activerecord-model_inheritance
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Moku S.r.l.
8
+ - Marco Volpato
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2023-07-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 7.0.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 7.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: activesupport
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 7.0.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 7.0.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: railties
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 7.0.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 7.0.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: scenic
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 1.7.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.7.0
70
+ description: An attempt at real inheritance for ActiveRecord models.
71
+ email:
72
+ - info@moku.io
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".rubocop.yml"
78
+ - CHANGELOG.md
79
+ - Gemfile
80
+ - LICENSE
81
+ - README.md
82
+ - Rakefile
83
+ - lib/active_record/model_inheritance.rb
84
+ - lib/active_record/model_inheritance/error.rb
85
+ - lib/active_record/model_inheritance/model.rb
86
+ - lib/active_record/model_inheritance/version.rb
87
+ - lib/active_record/model_inheritance/view_definition.rb
88
+ - lib/activerecord/model_inheritance.rb
89
+ - lib/generators/active_record/model_inheritance/generators.rb
90
+ - lib/generators/active_record/model_inheritance/model/model_generator.rb
91
+ - lib/generators/active_record/model_inheritance/model/templates/definition.erb
92
+ - lib/generators/active_record/model_inheritance/model/templates/model.erb
93
+ - lib/generators/active_record/model_inheritance/model/templates/model_config.erb
94
+ - lib/generators/active_record/model_inheritance/view/templates/create_migration.erb
95
+ - lib/generators/active_record/model_inheritance/view/templates/update_migration.erb
96
+ - lib/generators/active_record/model_inheritance/view/view_generator.rb
97
+ - sig/active_record/model_inheritance/generators/model_generator.rbs
98
+ - sig/active_record/model_inheritance/generators/view_generator.rbs
99
+ - sig/active_record/model_inheritance/version.rbs
100
+ - sig/active_record/model_inheritance/view_definition.rbs
101
+ homepage: https://github.com/moku-io/activerecord-model_inheritance
102
+ licenses:
103
+ - MIT
104
+ metadata:
105
+ homepage_uri: https://github.com/moku-io/activerecord-model_inheritance
106
+ source_code_uri: https://github.com/moku-io/activerecord-model_inheritance
107
+ changelog_uri: https://github.com/moku-io/activerecord-model_inheritance/blob/master/CHANGELOG.md
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 3.0.0
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubygems_version: 3.3.26
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: An attempt at real inheritance for ActiveRecord models.
127
+ test_files: []