yiffspace 0.1.8 → 0.2.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 (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -10
  3. data/README.md +18 -1
  4. data/Rakefile +6 -7
  5. data/lib/yiffspace/version.rb +1 -1
  6. data/lib/yiffspace.rb +26 -28
  7. metadata +104 -148
  8. data/app/assets/config/yiffspace_manifest.js +0 -1
  9. data/app/assets/stylesheets/yiffspace/application.css +0 -30
  10. data/app/controllers/yiff_space/application_controller.rb +0 -6
  11. data/app/helpers/yiff_space/application_helper.rb +0 -6
  12. data/app/models/yiff_space/application_record.rb +0 -7
  13. data/app/views/layouts/yiff_space/application.html.erb +0 -17
  14. data/app/views/yiff_space/error.html.erb +0 -3
  15. data/lib/generators/yiffspace/fixer/USAGE +0 -40
  16. data/lib/generators/yiffspace/fixer/fixer_generator.rb +0 -86
  17. data/lib/generators/yiffspace/fixer/templates/fixer.rb +0 -4
  18. data/lib/generators/yiffspace/install/fixes_generator.rb +0 -21
  19. data/lib/generators/yiffspace/install/templates/create_fixes.rb.erb +0 -18
  20. data/lib/tasks/fixes.rake +0 -66
  21. data/lib/yiffspace/concerns/active_record_extensions.rb +0 -45
  22. data/lib/yiffspace/concerns/api_methods.rb +0 -101
  23. data/lib/yiffspace/concerns/attribute_matchers.rb +0 -100
  24. data/lib/yiffspace/concerns/attribute_methods.rb +0 -39
  25. data/lib/yiffspace/concerns/concurrency_methods.rb +0 -20
  26. data/lib/yiffspace/concerns/conditional_includes.rb +0 -43
  27. data/lib/yiffspace/concerns/current_methods.rb +0 -60
  28. data/lib/yiffspace/concerns/has_bit_flags.rb +0 -59
  29. data/lib/yiffspace/concerns/user_class_methods.rb +0 -32
  30. data/lib/yiffspace/concerns/user_methods.rb +0 -77
  31. data/lib/yiffspace/concerns/user_name_methods.rb +0 -53
  32. data/lib/yiffspace/concerns/user_resolvable_methods.rb +0 -38
  33. data/lib/yiffspace/config_builder.rb +0 -192
  34. data/lib/yiffspace/configuration/fixer_templates.rb +0 -87
  35. data/lib/yiffspace/configuration/images.rb +0 -22
  36. data/lib/yiffspace/configuration.rb +0 -130
  37. data/lib/yiffspace/core_ext/active_record/all.rb +0 -8
  38. data/lib/yiffspace/core_ext/active_record/cross_join_lateral.rb +0 -7
  39. data/lib/yiffspace/core_ext/active_record/cross_unnest.rb +0 -7
  40. data/lib/yiffspace/core_ext/active_record/left_join_lateral.rb +0 -7
  41. data/lib/yiffspace/core_ext/active_record/left_unnest.rb +0 -7
  42. data/lib/yiffspace/core_ext/active_record/unnest.rb +0 -8
  43. data/lib/yiffspace/core_ext/active_record/where_chain.rb +0 -6
  44. data/lib/yiffspace/core_ext/all.rb +0 -8
  45. data/lib/yiffspace/core_ext/arel/all.rb +0 -4
  46. data/lib/yiffspace/core_ext/arel/cross_join_lateral.rb +0 -21
  47. data/lib/yiffspace/core_ext/arel/left_join_lateral.rb +0 -21
  48. data/lib/yiffspace/core_ext/enumerable/all.rb +0 -3
  49. data/lib/yiffspace/core_ext/enumerable/parallel.rb +0 -7
  50. data/lib/yiffspace/core_ext/hash/all.rb +0 -3
  51. data/lib/yiffspace/core_ext/hash/to_open_hash.rb +0 -7
  52. data/lib/yiffspace/core_ext/object/all.rb +0 -4
  53. data/lib/yiffspace/core_ext/object/to_b.rb +0 -7
  54. data/lib/yiffspace/core_ext/object/truthy_falsy.rb +0 -7
  55. data/lib/yiffspace/core_ext/string/all.rb +0 -3
  56. data/lib/yiffspace/core_ext/string/sql.rb +0 -7
  57. data/lib/yiffspace/engine.rb +0 -23
  58. data/lib/yiffspace/extensions/active_record/cross_join_lateral.rb +0 -23
  59. data/lib/yiffspace/extensions/active_record/cross_unnest.rb +0 -15
  60. data/lib/yiffspace/extensions/active_record/left_join_lateral.rb +0 -24
  61. data/lib/yiffspace/extensions/active_record/left_unnest.rb +0 -15
  62. data/lib/yiffspace/extensions/active_record/unnest.rb +0 -20
  63. data/lib/yiffspace/extensions/active_record/where_chain.rb +0 -107
  64. data/lib/yiffspace/extensions/arel/nodes/cross_join_lateral.rb +0 -17
  65. data/lib/yiffspace/extensions/arel/nodes/left_join_lateral.rb +0 -17
  66. data/lib/yiffspace/extensions/arel/table/cross_join_lateral.rb +0 -15
  67. data/lib/yiffspace/extensions/arel/table/left_join_lateral.rb +0 -15
  68. data/lib/yiffspace/extensions/arel/visitors/postgresql/cross_join_lateral.rb +0 -19
  69. data/lib/yiffspace/extensions/arel/visitors/postgresql/left_join_lateral.rb +0 -23
  70. data/lib/yiffspace/extensions/enumerable/parallel.rb +0 -39
  71. data/lib/yiffspace/extensions/hash/to_open_hash.rb +0 -15
  72. data/lib/yiffspace/extensions/object/to_b.rb +0 -22
  73. data/lib/yiffspace/extensions/object/truthy_falsy.rb +0 -35
  74. data/lib/yiffspace/extensions/string/sql.rb +0 -21
  75. data/lib/yiffspace/fix_tracker.rb +0 -95
  76. data/lib/yiffspace/fixer_template.rb +0 -44
  77. data/lib/yiffspace/images/avatar/base.rb +0 -41
  78. data/lib/yiffspace/images/avatar/discord.rb +0 -37
  79. data/lib/yiffspace/images/avatar/gravatar.rb +0 -21
  80. data/lib/yiffspace/images/avatar.rb +0 -33
  81. data/lib/yiffspace/images/banner/base.rb +0 -41
  82. data/lib/yiffspace/images/banner/discord.rb +0 -37
  83. data/lib/yiffspace/images/banner.rb +0 -33
  84. data/lib/yiffspace/images.rb +0 -6
  85. data/lib/yiffspace/include/active_record_extensions.rb +0 -5
  86. data/lib/yiffspace/include/all.rb +0 -31
  87. data/lib/yiffspace/include/api_methods.rb +0 -5
  88. data/lib/yiffspace/include/attribute_matchers.rb +0 -5
  89. data/lib/yiffspace/include/attribute_methods.rb +0 -5
  90. data/lib/yiffspace/include/cache.rb +0 -5
  91. data/lib/yiffspace/include/concurrency_methods.rb +0 -5
  92. data/lib/yiffspace/include/conditional_includes.rb +0 -5
  93. data/lib/yiffspace/include/current.rb +0 -5
  94. data/lib/yiffspace/include/current_methods.rb +0 -5
  95. data/lib/yiffspace/include/duration_parser.rb +0 -5
  96. data/lib/yiffspace/include/has_bit_flags.rb +0 -5
  97. data/lib/yiffspace/include/helpers.rb +0 -5
  98. data/lib/yiffspace/include/open_hash.rb +0 -5
  99. data/lib/yiffspace/include/parameter_builder.rb +0 -5
  100. data/lib/yiffspace/include/parse_value.rb +0 -5
  101. data/lib/yiffspace/include/query_builder.rb +0 -5
  102. data/lib/yiffspace/include/query_dsl.rb +0 -5
  103. data/lib/yiffspace/include/query_helper.rb +0 -5
  104. data/lib/yiffspace/include/routes.rb +0 -5
  105. data/lib/yiffspace/include/table_builder.rb +0 -5
  106. data/lib/yiffspace/include/trace_logger.rb +0 -5
  107. data/lib/yiffspace/include/u2id.rb +0 -5
  108. data/lib/yiffspace/include/user_attribute.rb +0 -5
  109. data/lib/yiffspace/include/user_class_methods.rb +0 -5
  110. data/lib/yiffspace/include/user_like.rb +0 -5
  111. data/lib/yiffspace/include/user_methods.rb +0 -5
  112. data/lib/yiffspace/include/user_name_methods.rb +0 -5
  113. data/lib/yiffspace/include/user_resolvable.rb +0 -5
  114. data/lib/yiffspace/include/user_resolvable_methods.rb +0 -5
  115. data/lib/yiffspace/search/query_builder.rb +0 -83
  116. data/lib/yiffspace/search/query_dsl.rb +0 -119
  117. data/lib/yiffspace/search/query_helper.rb +0 -49
  118. data/lib/yiffspace/serializers/avatar_serializer.rb +0 -21
  119. data/lib/yiffspace/serializers/banner_serializer.rb +0 -21
  120. data/lib/yiffspace/serializers/user_resolvable_serializer.rb +0 -21
  121. data/lib/yiffspace/utils/cache.rb +0 -40
  122. data/lib/yiffspace/utils/current.rb +0 -43
  123. data/lib/yiffspace/utils/duration_parser.rb +0 -24
  124. data/lib/yiffspace/utils/helpers.rb +0 -25
  125. data/lib/yiffspace/utils/open_hash.rb +0 -63
  126. data/lib/yiffspace/utils/parameter_builder.rb +0 -121
  127. data/lib/yiffspace/utils/parse_value.rb +0 -174
  128. data/lib/yiffspace/utils/routes.rb +0 -28
  129. data/lib/yiffspace/utils/set_env_constraint.rb +0 -18
  130. data/lib/yiffspace/utils/table_builder.rb +0 -169
  131. data/lib/yiffspace/utils/trace_logger.rb +0 -91
  132. data/lib/yiffspace/utils/user_attribute.rb +0 -272
  133. data/lib/yiffspace/utils/user_like.rb +0 -8
  134. data/lib/yiffspace/utils/user_resolvable.rb +0 -61
  135. data/lib/yiffspace/utils/user_to_id.rb +0 -11
  136. data/lib/yiffspace/utils.rb +0 -6
@@ -1,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Yiffspace
4
- # Scaffolds a new db/fixes/*.rb script for YiffSpace::FixTracker (see `rake fixes:list`).
5
- #
6
- # `--steps N` splits the fix into N ordered steps sharing an id, each one a copy of the generic
7
- # fixer.rb template. A host app can instead define a YiffSpace::FixerTemplate subclass (see that
8
- # class) to control both the step count and each step's file content, auto-discovered from
9
- # YiffSpace.config.fixer_templates_path - reachable here with `--template <name>`/`-t <name>`,
10
- # or with the template's own shortname flag if it registered one (e.g. `-e`).
11
- class FixerGenerator < Rails::Generators::NamedBase
12
- source_root(File.expand_path("templates", __dir__))
13
- # No short alias - -s/-f/-p/-q are already claimed by Rails::Generators::Base's own runtime
14
- # options (--skip/--force/--pretend/--quiet), and Thor silently lets the last-defined
15
- # class_option win a collision instead of erroring.
16
- class_option(:steps, type: :numeric, default: 1,
17
- desc: "Split the fix into N ordered steps sharing an id, e.g. 12_1_name.rb, 12_2_name.rb")
18
- class_option(:template, type: :string, default: nil, aliases: ["-t"],
19
- desc: "Use a fixer template registered with YiffSpace.config.fixer_templates")
20
-
21
- YiffSpace.config.fixer_templates.each do |template|
22
- next unless template.short
23
-
24
- class_option(template.name.to_sym, type: :boolean, default: false, aliases: ["-#{template.short}"],
25
- desc: "Shortcut for --template #{template.name}")
26
- end
27
-
28
- def create_fixer
29
- content_blocks = resolve_content_blocks
30
-
31
- id = Dir[File.join(destination_root, "db/fixes/*.rb")].map { |f| File.basename(f, ".rb").split("_").first.to_i }.max.to_i + 1
32
-
33
- if content_blocks.size == 1
34
- create_fixer_file("db/fixes/#{id}_#{file_name}.rb", content_blocks.first)
35
- else
36
- content_blocks.each_with_index { |block, index| create_fixer_file("db/fixes/#{id}_#{index + 1}_#{file_name}.rb", block) }
37
- end
38
- end
39
-
40
- private
41
-
42
- # One entry per step - a block returning that step's file content, or nil to fall back to
43
- # copying the generic fixer.rb template (a plain --steps N, or a manually
44
- # YiffSpace.config.fixer_templates.register'd template, has no per-step content).
45
- def resolve_content_blocks
46
- template = resolve_template
47
- return template.content_blocks if template
48
-
49
- Array.new(steps_from_flag)
50
- end
51
-
52
- def resolve_template
53
- name = template_name
54
- return nil if name.nil?
55
-
56
- template = YiffSpace.config.fixer_templates[name]
57
- raise(Thor::Error, "no fixer template named #{name.inspect} is registered") unless template
58
-
59
- template
60
- end
61
-
62
- # The template chosen via `--template <name>`, or via a registered template's own shortname
63
- # flag (e.g. `-e` for a template registered with `short: "e"`) - nil if neither was passed.
64
- def template_name
65
- return options["template"] if options["template"]
66
-
67
- YiffSpace.config.fixer_templates.find { |template| template.short && options[template.name] }&.name
68
- end
69
-
70
- def steps_from_flag
71
- steps = options["steps"].to_i
72
- raise(Thor::Error, "--steps must be at least 1") if steps < 1
73
-
74
- steps
75
- end
76
-
77
- def create_fixer_file(path, content_block)
78
- if content_block
79
- create_file(path, content_block.call)
80
- chmod(path, "+x")
81
- else
82
- copy_file("fixer.rb", path, mode: :preserve)
83
- end
84
- end
85
- end
86
- end
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "config", "environment")))
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Yiffspace
4
- module Install
5
- # Installs YiffSpace::FixTracker into a host app: `bin/rails generate yiffspace:install:fixes`
6
- # copies the `fixes` tracking table migration. Run `bin/rails db:migrate` afterwards.
7
- class FixesGenerator < Rails::Generators::Base
8
- include(Rails::Generators::Migration)
9
-
10
- source_root(File.expand_path("templates", __dir__))
11
-
12
- def self.next_migration_number(dirname)
13
- ActiveRecord::Migration.next_migration_number(current_migration_number(dirname) + 1)
14
- end
15
-
16
- def create_migration_file
17
- migration_template("create_fixes.rb.erb", "db/migrate/create_fixes.rb")
18
- end
19
- end
20
- end
21
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Tracks which db/fixes/*.rb scripts have been applied, the same way schema_migrations tracks
4
- # migrations - see YiffSpace::FixTracker and `rake fixes:migrate`/`rake fixes:list`.
5
- #
6
- # `id` is the fix's own leading number (e.g. 12, 23), not a surrogate key, so it isn't unique on
7
- # its own - a fix can be split into ordered sub-steps (12_1, 12_2, ...) that share an id and are
8
- # distinguished by `index`. `index` is null for fixes with no subtype.
9
- class CreateFixes < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
10
- def change
11
- create_table(:fixes, id: false) do |t|
12
- t.integer(:id, null: false) # not a surrogate key, this is the fix's own leading number
13
- t.integer(:index)
14
- end
15
-
16
- add_index(:fixes, %i[id index], unique: true, nulls_not_distinct: true)
17
- end
18
- end
data/lib/tasks/fixes.rake DELETED
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Keep structure.sql's fixes rows in sync with the database on every schema dump, the same way
4
- # ActiveRecord keeps schema_migrations rows in sync - not just when `fixes:migrate` runs.
5
- Rake::Task["db:schema:dump"].enhance do
6
- YiffSpace::FixTracker.dump_structure_sql!
7
- end
8
-
9
- namespace(:fixes) do
10
- desc("List available fix scripts in db/fixes, marking which have already been applied")
11
- task(list: :environment) do
12
- applied = YiffSpace::FixTracker.applied
13
- YiffSpace::FixTracker.all_fixes.each do |name|
14
- puts("#{applied.include?(YiffSpace::FixTracker.key_for(name)) ? '[x]' : '[ ]'} #{name}")
15
- end
16
- end
17
-
18
- desc("Run a fix script from db/fixes by id or name, e.g. `rake fixes:run[1]` - re-runs even if already recorded as applied")
19
- task(:run, [:name] => :environment) do |_task, args|
20
- name = args[:name].to_s.delete_suffix(".rb")
21
- abort("Usage: rake fixes:run[id_or_name] (see `rake fixes:list`)") if name.blank?
22
-
23
- candidates = Dir["db/fixes/*.rb"]
24
- exact = candidates.find { |path| File.basename(path, ".rb") == name }
25
- matches = exact ? [exact] : candidates.select { |path| File.basename(path, ".rb").start_with?("#{name}_") || File.basename(path, ".rb").include?(name) }
26
-
27
- if matches.empty?
28
- abort("No fix matches \"#{name}\". Run `rake fixes:list` to see available fixes.")
29
- elsif matches.size > 1
30
- abort("Multiple fixes match \"#{name}\", be more specific:\n#{matches.map { |m| " #{File.basename(m, '.rb')}" }.join("\n")}")
31
- end
32
-
33
- puts("Running #{File.basename(matches.first, '.rb')}...")
34
- name = YiffSpace::FixTracker.run!(matches.first)
35
- puts("Recorded #{name} as applied")
36
- end
37
-
38
- desc("Apply all fix scripts not yet recorded as applied, in order, then dump the schema like db:migrate does")
39
- task(migrate: :environment) do
40
- pending = YiffSpace::FixTracker.pending
41
-
42
- if pending.empty?
43
- puts("No pending fixes.")
44
- else
45
- pending.each do |name|
46
- puts("Running #{name}...")
47
- YiffSpace::FixTracker.run!(YiffSpace::FixTracker.fix_path(name))
48
- puts("Recorded #{name} as applied")
49
- end
50
- end
51
-
52
- Rake::Task["db:_dump"].invoke
53
- end
54
-
55
- desc("Record all of the current fixes as having been applied")
56
- task(load: :environment) do
57
- list = YiffSpace::FixTracker.all_fixes.map { YiffSpace::FixTracker.key_for(it) }
58
- existing = ActiveRecord::Base.connection.select_all('SELECT id, "index" FROM fixes ORDER BY id, "index"').rows
59
- list.reject! { |id, index| existing.any? { |e| e[0] == id && e[1] == index } }
60
- unless list.empty?
61
- values = list.map { |id, index| "(#{id}, #{index.nil? ? 'NULL' : index})" }.join(", ")
62
- ActiveRecord::Base.connection.execute(%(INSERT INTO fixes (id, "index") VALUES #{values}))
63
- end
64
- puts("Loaded #{list.length} #{'fix'.pluralize(list.length)}")
65
- end
66
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Concerns
5
- module ActiveRecordExtensions
6
- extend(ActiveSupport::Concern)
7
-
8
- module ClassMethods
9
- def without_timeout
10
- original = statement_timeout
11
- connection.execute("SET STATEMENT_TIMEOUT = 0") unless Rails.env.test?
12
- yield
13
- ensure
14
- connection.execute("SET STATEMENT_TIMEOUT = #{original}") unless Rails.env.test?
15
- end
16
-
17
- def with_timeout(time, default_value = nil)
18
- original = statement_timeout
19
- connection.execute("SET STATEMENT_TIMEOUT = #{time}") unless Rails.env.test?
20
- yield
21
- rescue ::ActiveRecord::StatementInvalid => e
22
- Rails.logger.warn("Statement timeout exceeded: #{e.message}")
23
- default_value
24
- ensure
25
- connection.execute("SET STATEMENT_TIMEOUT = #{original}") unless Rails.env.test?
26
- end
27
-
28
- def statement_timeout
29
- YiffSpace.config.application_record_class.connection.select_one("SELECT setting FROM pg_settings WHERE name = 'statement_timeout'")["setting"].to_i
30
- end
31
-
32
- # CrossJoinLateral, LeftJoinLateral, nil
33
- def unnest(column, name: column.singularize, type: ::Arel::Nodes::LeftJoinLateral)
34
- function = ::Arel::Nodes::NamedFunction.new("unnest", [arel(column)], name)
35
- return function if type.nil?
36
-
37
- joins(type.new(
38
- function,
39
- ::Arel::Nodes::On.new(Arel.sql("TRUE")),
40
- ))
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Concerns
5
- module ApiMethods
6
- class NotVisibleError < StandardError; end
7
- extend(ActiveSupport::Concern)
8
-
9
- module ClassMethods
10
- def available_includes
11
- []
12
- end
13
-
14
- def multiple_includes
15
- reflections.select { |_, v| v.macro == :has_many }.keys.map(&:to_sym)
16
- end
17
-
18
- def associated_models(name)
19
- if reflections[name].options[:polymorphic]
20
- reflections[name].active_record.try(:model_types) || []
21
- else
22
- [reflections[name].class_name]
23
- end
24
- end
25
- end
26
-
27
- delegate(:available_includes, to: :class)
28
-
29
- # XXX deprecated, shouldn't expose this as an instance method.
30
- def api_attributes(user)
31
- policy = Pundit.policy(user, self) || ApplicationPolicy.new(user, self)
32
- policy.api_attributes
33
- end
34
-
35
- # XXX deprecated, shouldn't expose this as an instance method.
36
- def html_data_attributes(user)
37
- policy = Pundit.policy(user, self) || ApplicationPolicy.new(user, self)
38
- policy.html_data_attributes
39
- end
40
-
41
- def process_api_attributes(options, underscore: false)
42
- options[:methods] ||= []
43
- attributes, methods = api_attributes(options[:user]).partition { |attr| has_attribute?(attr) }
44
- methods += options[:methods]
45
- if underscore && options[:only].blank?
46
- options[:only] = attributes + methods
47
- else
48
- options[:only] ||= attributes + methods
49
- end
50
-
51
- attributes &= options[:only]
52
- methods &= options[:only]
53
-
54
- options[:only] = attributes
55
- options[:methods] = methods
56
-
57
- options.delete(:methods) if options[:methods].empty?
58
- options
59
- end
60
-
61
- def serializable_hash(options = {})
62
- options ||= {}
63
- options[:user] ||= CurrentUser.user || User.anonymous
64
- return :not_visible unless visible?(options[:user])
65
-
66
- if options[:only].is_a?(String)
67
- options.delete(:methods)
68
- options.delete(:include)
69
- options.merge!(ParameterBuilder.serial_parameters(options[:only], self, options))
70
- if options[:only].include?("_")
71
- options[:only].delete("_")
72
- options = process_api_attributes(options, underscore: true)
73
- end
74
- else
75
- options = process_api_attributes(options)
76
- end
77
- options[:only] += [SecureRandom.hex(6)]
78
-
79
- hash = super
80
- hash.transform_keys! { |key| key.delete("?").delete_prefix("apionly_") }
81
- deep_reject_hash(hash) { |_, v| v == :not_visible }
82
- end
83
-
84
- def visible?(_user)
85
- true
86
- end
87
-
88
- def deep_reject_hash(hash, &block)
89
- hash.each_with_object({}) do |(key, value), result|
90
- if value.is_a?(Hash)
91
- result[key] = deep_reject_hash(value, &block)
92
- elsif value.is_a?(Array)
93
- result[key] = value.map { |v| v.is_a?(Hash) ? deep_reject_hash(v, &block) : v }.reject { |i| block.call(nil, i) }
94
- elsif !block.call(key, value)
95
- result[key] = value
96
- end
97
- end
98
- end
99
- end
100
- end
101
- end
@@ -1,100 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Concerns
5
- module AttributeMatchers
6
- def boolean_attribute_matches(attribute, value, &)
7
- return all if value.nil?
8
-
9
- if value.to_s.truthy?
10
- value = true
11
- elsif value.to_s.falsy?
12
- value = false
13
- else
14
- raise(ArgumentError, "value must be truthy or falsy")
15
- end
16
-
17
- q = block_given? ? yield : all
18
- q.where(attribute => value)
19
- end
20
-
21
- # range: "5", ">5", "<5", ">=5", "<=5", "5..10", "5,6,7"
22
- def numeric_attribute_matches(attribute, value, &)
23
- return all if value.nil?
24
-
25
- value = value.to_s.strip
26
- column = QueryHelper.get_column(attribute, table_name)
27
- parsed_range = ParseValue.range(value, column.type)
28
-
29
- add_range_relation(parsed_range, attribute, &)
30
- end
31
-
32
- # datetime columns return ActiveSupport::TimeWithZone
33
- def datetime_attribute_matches(attribute, range, &)
34
- numeric_attribute_matches(attribute, range, &)
35
- end
36
-
37
- def add_range_relation(arr, field, &)
38
- return all if arr.nil?
39
-
40
- q = block_given? ? yield : all
41
- case arr[0]
42
- when :eq
43
- if arr[1].is_a?(Time)
44
- q.where.between(field => arr[1].all_day)
45
- else
46
- q.where(field => arr[1])
47
- end
48
- when :gt
49
- q.where.gt(field => arr[1])
50
- when :gte
51
- q.where.gte(field => arr[1])
52
- when :lt
53
- q.where.lt(field => arr[1])
54
- when :lte
55
- q.where.lte(field => arr[1])
56
- when :in
57
- q.where.in(field => arr[1])
58
- when :between
59
- q.where.between(field => arr[1]..arr[2])
60
- else
61
- q.none
62
- end
63
- end
64
-
65
- def text_attribute_matches(attribute, value, convert_to_wildcard: false, &)
66
- return all if value.nil?
67
-
68
- value = "*#{value}*" if convert_to_wildcard && value.exclude?("*")
69
- q = block_given? ? yield : all
70
- if value.is_a?(Array)
71
- q.where.ilike_any(attribute => value)
72
- elsif value =~ /\*/
73
- q.where.ilike(attribute => value)
74
- else
75
- q.where.tsquery(attribute => value)
76
- end
77
- end
78
-
79
- def ip_attribute_matches(attribute, value, &)
80
- return all if value.nil?
81
-
82
- q = block_given? ? yield : all
83
- q.where.inet_contained_within_or_equals(attribute => value)
84
- end
85
-
86
- def attribute_present(attribute, value, &)
87
- return all if value.nil?
88
-
89
- q = block_given? ? yield : all
90
- if value.to_s.truthy?
91
- q.where.not(attribute => nil)
92
- elsif value.to_s.falsy?
93
- q.where(attribute => nil)
94
- else
95
- q.none
96
- end
97
- end
98
- end
99
- end
100
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Concerns
5
- module AttributeMethods
6
- extend(ActiveSupport::Concern)
7
-
8
- module ClassMethods
9
- # Defines `<attribute>_string`, `<attribute>_string=`, and `<attribute>=`
10
- # methods for converting an array attribute to or from a string.
11
- #
12
- # The `<attribute>=` setter parses strings into an array using the
13
- # `parse` regex. The resulting strings can be converted to another type
14
- # with the `cast` option.
15
- def array_attribute(name, parse: /[^[:space:]]+/, join_character: " ", cast: :itself)
16
- define_method("#{name}_string") do
17
- send(name).join(join_character)
18
- end
19
-
20
- define_method("#{name}_string=") do |value|
21
- raise(ArgumentError, "#{name} must be a String") unless value.respond_to?(:to_str)
22
-
23
- send("#{name}=", value)
24
- end
25
-
26
- define_method("#{name}=") do |value|
27
- if value.respond_to?(:to_str)
28
- super(value.to_str.scan(parse).flatten.map(&cast))
29
- elsif value.respond_to?(:to_a)
30
- super(value.to_a)
31
- else
32
- raise(ArgumentError, "#{name} must be a String or an Array")
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Concerns
5
- module ConcurrencyMethods
6
- extend(ActiveSupport::Concern)
7
-
8
- class_methods do
9
- def parallel_find_each(**, &)
10
- # XXX We may deadlock if a transaction is open; do a non-parallel each.
11
- return find_each(&) if connection.transaction_open?
12
-
13
- find_in_batches(error_on_ignore: true, **) do |batch|
14
- batch.parallel_each(&)
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Concerns
5
- module ConditionalIncludes
6
- extend(ActiveSupport::Concern)
7
-
8
- module ClassMethods
9
- def html_includes(request, *)
10
- includes_if(request.format.html?, *)
11
- end
12
-
13
- def includes_if(condition, *)
14
- return all unless condition
15
-
16
- includes(*)
17
- end
18
-
19
- def includes_unless(condition, *)
20
- return all if condition
21
-
22
- includes(*)
23
- end
24
-
25
- def html_preload(request, *)
26
- preload_if(request.format.html?, *)
27
- end
28
-
29
- def preload_if(condition, *)
30
- return all unless condition
31
-
32
- preload(*)
33
- end
34
-
35
- def preload_unless(condition, *)
36
- return all if condition
37
-
38
- preload(*)
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Concerns
5
- module CurrentMethods
6
- extend(ActiveSupport::Concern)
7
-
8
- module ClassMethods
9
- def search_current(params, ...)
10
- search(params, YiffSpace.config.current_class.user, ...)
11
- end
12
-
13
- def with_current(instance, method, *args, **, &)
14
- attr = args.grep(Symbol)
15
- other = args - attr
16
- hashes = other.grep(Hash)
17
- params = other.grep(ActionController::Parameters)
18
- other -= hashes + params
19
- other.compact_blank!
20
- options = [attr.index_with(YiffSpace.config.current_class.user), *hashes, *params.map(&:to_hash)].inject(:merge)
21
- instance.send(method, *other, **options, **, &)
22
- end
23
-
24
- def new_with_current(...)
25
- with_current(self, :new, ...)
26
- end
27
-
28
- def create_with_current(...)
29
- with_current(self, :create, ...)
30
- end
31
-
32
- def create_with_current!(...)
33
- with_current(self, :create!, ...)
34
- end
35
- end
36
-
37
- def update_with_current(...)
38
- self.class.with_current(self, :update, ...)
39
- end
40
-
41
- def update_with_current!(...)
42
- self.class.with_current(self, :update!, ...)
43
- end
44
-
45
- def destroy_with_current(*attrs)
46
- attrs.each do |attr|
47
- send("#{attr}=", YiffSpace.config.current_class.user)
48
- end
49
- destroy
50
- end
51
-
52
- def destroy_with_current!(*attrs)
53
- attrs.each do |attr|
54
- send("#{attr}=", YiffSpace.config.current_class.user)
55
- end
56
- destroy!
57
- end
58
- end
59
- end
60
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Concerns
5
- module HasBitFlags
6
- extend(ActiveSupport::Concern)
7
-
8
- module ClassMethods
9
- # NOTE: the ordering of attributes has to be fixed
10
- # new attributes should be appended to the end.
11
- def has_bit_flags(attributes, options = {})
12
- field = options[:field] || :bit_flags
13
-
14
- define_singleton_method("flag_value_for") do |key|
15
- value = attributes[key.to_s]
16
- return value if value
17
-
18
- raise(ArgumentError, "Invalid flag: #{key}")
19
- end
20
-
21
- attributes.each do |name, value|
22
- scope(name.to_sym, -> { where.has_bits(field => value) })
23
- define_method(name) do
24
- send(field) & value == value
25
- end
26
-
27
- define_method("#{name}=") do |val|
28
- if val.to_s =~ /[t1y]/
29
- send("#{field}=", send(field) | value)
30
- else
31
- send("#{field}=", send(field) & ~value)
32
- end
33
- end
34
-
35
- define_method("#{name}_was") do
36
- send("#{field}_was") & value == value
37
- end
38
-
39
- define_method("#{name}_before_last_save") do
40
- send("#{field}_before_last_save") & value == value
41
- end
42
-
43
- alias_method("#{name}?", name)
44
- alias_method("#{name}_before_last_save?", "#{name}_before_last_save")
45
- alias_method("#{name}_was?", "#{name}_was")
46
-
47
- define_method("#{name}_changed?") do
48
- send("#{name}_was") != send(name)
49
- end
50
-
51
- define_method("saved_change_to_#{name}?") do
52
- send("#{name}_before_last_save") != send(name)
53
- end
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end