Module: Sequel::Plugins::UnusedAssociations::ClassMethods

Defined in:
lib/sequel/plugins/unused_associations.rb

Instance Method Summary collapse

Instance Method Details

#associate(type, assoc_name, opts = OPTS) ⇒ Object

If modifying associations, and this association is marked as not used, and the association does not include the specific :is_used option, skip defining the association.


284
285
286
287
288
289
290
# File 'lib/sequel/plugins/unused_associations.rb', line 284

def associate(type, assoc_name, opts=OPTS)
  if !opts[:is_used] && @unused_associations_data && (data = @unused_associations_data[name]) && data[assoc_name.to_s] == 'unused'
    return
  end
  
  super
end

#association_reflection(association) ⇒ Object

Record access to association reflections to determine which associations are not used.


275
276
277
278
279
# File 'lib/sequel/plugins/unused_associations.rb', line 275

def association_reflection(association)
  uar = used_association_reflections
  Sequel.synchronize{uar[association] ||= true}
  super
end

#delete_unused_associations_filesObject

Delete the unused associations coverage file and unused associations data file, if either exist.


461
462
463
464
# File 'lib/sequel/plugins/unused_associations.rb', line 461

def delete_unused_associations_files
  _delete_unused_associations_file(@unused_associations_coverage_file)
  _delete_unused_associations_file(@unused_associations_file)
end

#freezeObject

Setup the used_association_reflections storage before freezing


293
294
295
296
# File 'lib/sequel/plugins/unused_associations.rb', line 293

def freeze
  used_association_reflections
  super
end

#unused_association_options(opts = OPTS) ⇒ Object

Return an array of unused association options. These are associations some but not all of the association methods are used, according to the coverage information. Each entry in the array is an array of three elements. The first element is the class name string, the second element is the association name string, and the third element is a hash of association options that can be used in the association so it does not define methods that are not used.

Options:

:unused_associations_data

The data to use for determining which associations are unused, which is returned from update_unused_associations_data. If not given, loads the data from the file specified by the :file plugin option.


445
446
447
448
449
450
451
452
453
454
455
456
457
# File 'lib/sequel/plugins/unused_associations.rb', line 445

def unused_association_options(opts=OPTS)
  unused_associations_data = opts[:unused_associations_data] || Sequel.parse_json(File.binread(@unused_associations_file))

  unused_association_methods = []
  unused_associations_data.each do |sc, associations|
    associations.each do |assoc, unused|
      unless unused == 'unused'
        unused_association_methods << [sc, assoc, set_unused_options_for_association({}, unused)]
      end
    end
  end
  unused_association_methods
end

#unused_associations(opts = OPTS) ⇒ Object

Return an array of unused associations. These are associations where none of the association methods are used, according to the coverage information. Each entry in the array is an array of two strings, with the first string being the class name and the second string being the association name.

Options:

:unused_associations_data

The data to use for determining which associations are unused, which is returned from update_unused_associations_data. If not given, loads the data from the file specified by the :file plugin option.


418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/sequel/plugins/unused_associations.rb', line 418

def unused_associations(opts=OPTS)
  unused_associations_data = opts[:unused_associations_data] || Sequel.parse_json(File.binread(@unused_associations_file))

  unused_associations = []
  unused_associations_data.each do |sc, associations|
    associations.each do |assoc, unused|
      if unused == 'unused'
        unused_associations << [sc, assoc]
      end
    end
  end
  unused_associations
end

#update_associations_coverage(opts = OPTS) ⇒ Object

Parse the coverage result, and return the coverage data for the associations for descendants of this class. If the plugin uses the :coverage_file option, the existing coverage file will be loaded if present, and before the method returns, the coverage file will be updated.

Options:

:coverage_result

The coverage result to use. This defaults to Coverage.result.


305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/sequel/plugins/unused_associations.rb', line 305

def update_associations_coverage(opts=OPTS)
  coverage_result = opts[:coverage_result] || Coverage.result
  module_mapping = {}
  file = @unused_associations_coverage_file

  coverage_data = if file && File.file?(file)
    Sequel.parse_json(File.binread(file))
  else
    {}
  end

  ([self] + descendents).each do |sc|
    next if sc.associations.empty? || !sc.name
    module_mapping[sc.send(:overridable_methods_module)] = sc
    cov_data = coverage_data[sc.name] ||= {''=>[]}
    cov_data[''].concat(sc.used_association_reflections.keys.map(&:to_s).sort).uniq!
  end

  coverage_result.each do |file, coverage|
    coverage[:methods].each do |(mod, meth), times|
      next unless sc = module_mapping[mod]
      coverage_data[sc.name][meth.to_s] ||= 0
      coverage_data[sc.name][meth.to_s] += times
    end
  end

  if file
    File.binwrite(file, Sequel.object_to_json(coverage_data))
  end

  coverage_data
end

#update_unused_associations_data(options = OPTS) ⇒ Object

Parse the coverage data returned by #update_associations_coverage, and return data on unused associations and unused association methods.

Options:

:coverage_data

The coverage data to use. If not given, it is taken from the file specified by the :coverage_file plugin option.

:keep_coverage

Do not delete the file specified by the :coverage_file plugin option, even if it exists.


346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/sequel/plugins/unused_associations.rb', line 346

def update_unused_associations_data(options=OPTS)
  coverage_data = options[:coverage_data] || Sequel.parse_json(File.binread(@unused_associations_coverage_file))

  unused_associations_data = {}

  ([self] + descendents).each do |sc|
    next unless cov_data = coverage_data[sc.name]
    reflection_data = cov_data[''] || []

    sc.association_reflections.each do |assoc, ref|
      # Only report associations for the class they are defined in
      next unless ref[:model] == sc

      # Do not report associations using methods_module option, because this plugin only
      # looks in the class's overridable_methods_module
      next if ref[:methods_module]

      info = {}
      if reflection_data.include?(assoc.to_s)
        info[:used] = [:reflection]
      end

      _update_association_coverage_info(info, cov_data, ref.dataset_method, :dataset_method)
      _update_association_coverage_info(info, cov_data, ref.association_method, :association_method)

      unless ref[:orig_opts][:read_only]
        if ref.returns_array?
          _update_association_coverage_info(info, cov_data, ref[:add_method], :adder)
          _update_association_coverage_info(info, cov_data, ref[:remove_method], :remover)
          _update_association_coverage_info(info, cov_data, ref[:remove_all_method], :clearer)
        else
          _update_association_coverage_info(info, cov_data, ref[:setter_method], :setter)
        end
      end

      next if info.keys == [:missing]

      if !info[:used]
        (unused_associations_data[sc.name] ||= {})[assoc.to_s] = 'unused'
      elsif unused = info[:unused]
        if unused.include?(:setter) || [:adder, :remover, :clearer].all?{|k| unused.include?(k)}
          [:setter, :adder, :remover, :clearer].each do |k|
            unused.delete(k)
          end
          unused << :read_only
        end
        (unused_associations_data[sc.name] ||= {})[assoc.to_s] = unused.map(&:to_s)
      end
    end
  end

  if @unused_associations_file
    File.binwrite(@unused_associations_file, Sequel.object_to_json(unused_associations_data))
  end
  unless options[:keep_coverage]
    _delete_unused_associations_file(@unused_associations_coverage_file)
  end

  unused_associations_data
end

#used_association_reflectionsObject

Synchronize access to the used association reflections.


270
271
272
# File 'lib/sequel/plugins/unused_associations.rb', line 270

def used_association_reflections
  Sequel.synchronize{@used_association_reflections ||= {}}
end