module PrettyAssociationInspect

モデルに関連情報を見やすく表示するメソッドを定義します。

Constants

VERSION

Public Instance Methods

all_models_define() click to toggle source

全てのモデルにメソッドを定義する

# File lib/pretty_association_inspect.rb, line 217
def all_models_define
  model_names_array = load_all_models
  model_names_array.each do |model_name|
    begin
      klass = eval(model_name)
      pretty_association_inspect_define(klass)
    rescue
      next
    end
  end
end
build_association_hash(model) click to toggle source

アソシエーションをハッシュに変換

# File lib/pretty_association_inspect.rb, line 157
def build_association_hash(model)
  pretty_hash = model.reflect_on_all_associations.each_with_object({}) do |m, hash|
    name = m.class.to_s.gsub("ActiveRecord::Reflection::", "").gsub("Reflection", "").to_sym
    hash[name] ||= []
    human_name = PrettyAssociationInspect.jp_scripe(m.klass.model_name.human)
    hash[name] << [
      m.name, human_name
    ].compact.join(' | ')
    hash[name] = hash[name]
  end
end
build_association_node(start, max_cost) click to toggle source
# File lib/pretty_association_inspect.rb, line 80
def build_association_node(start, max_cost)
  models = ActiveRecord::Base.subclasses.map(&:name)
  data = models.each_with_object({}) do |model_name_str, hash|
    eval(model_name_str).reflect_on_all_associations.each do |m|
      model_single_name   = eval(model_name_str).model_name.singular.to_sym
      model_multiple_name = eval(model_name_str).model_name.plural.to_sym
      hash[model_single_name]   ||= []
      hash[model_multiple_name] ||= []
      hash[model_single_name]   << [1, m.name]
      hash[model_multiple_name] << [1, m.name]
    end
  end
  graph = Graph.new(data)
  route_hash = {}
  data.each do |goal, v|
    next if start == goal
    new_route = graph.print_route(graph.minimum_route(start, goal, max_cost))
    _model_ = ActiveRecord::Base.module_eval(goal.to_s.camelize.singularize).model_name.human rescue nil
    human_str = PrettyAssociationInspect.jp_scripe(_model_)
    route_hash["#{goal} #{human_str}"] = new_route if new_route
  end
  route_hash
end
jp_scripe(str) click to toggle source

日本語だけ抽出

# File lib/pretty_association_inspect.rb, line 211
def jp_scripe(str)
  japanese = Regexp.new(/[亜-熙ぁ-んァ-ヶ]/)
  str if japanese =~ str
end
load_all_models() click to toggle source

全てのモデルを読み込み、モデル名配列を返す

# File lib/pretty_association_inspect.rb, line 230
def load_all_models
  models_file_path = Dir.glob(Rails.root.join("app/models/*")).grep(/rb\z/)
  models_file_path.each { |m| require(m) rescue next }
  return ActiveRecord::Base.subclasses.map(&:name)
end
pretty_association_inspect_define(klass) click to toggle source

『関連を可愛く表示するメソッド』を定義する

# File lib/pretty_association_inspect.rb, line 106
def pretty_association_inspect_define(klass)
  klass.class_eval do |model|
    self.define_singleton_method(:to){
      associations_hash = PrettyAssociationInspect.build_association_hash(model)
      PrettyAssociationInspect.printed(klass, model, associations_hash)
      return self.first || self
    }

    define_method(:to){
      associations_hash = PrettyAssociationInspect.build_association_hash(model)
      PrettyAssociationInspect.printed(klass, model, associations_hash)
      return self
    }
    self.define_singleton_method(:toto){ |max_cost=1, start = nil|
      model_name_sym = model_name.singular.to_sym
      route_arr = PrettyAssociationInspect.build_association_node(start || model_name_sym, max_cost)
      ap route_arr.map { |route| [route.first, eval(route.last.to_s)] rescue nil }
      ap route_arr
      return nil
    }
    define_method(:toto){ |max_cost = 1, start = nil|
      model_name_sym = model_name.singular.to_sym
      route_arr = PrettyAssociationInspect.build_association_node(start || model_name_sym, max_cost)
      ap route_arr.map { |route| [route.first, eval(route.last.to_s)] rescue nil }
      ap route_arr
      return nil
    }
    self.define_singleton_method(:s){ |name = nil|
      results = Module.const_get(self.to_s).columns.select{|m| m.sql_type=~/char/}.map(&:name).map(&:to_sym).each_with_object([]) { |attr, records|
        result   = self.where(self.arel_table[attr].matches("%#{name}%"))
        records << [attr, result.ids, result]
      }.select{|m| m.second.present? }
      ap results
      result_where = self.where(id: results.map(&:second).flatten)
      ap result_where
      return result_where
    }
  end
end
printed(klass, model, associations_hash) click to toggle source

表示

# File lib/pretty_association_inspect.rb, line 170
def printed(klass, model, associations_hash)
  pretty_hash = {}
  begin
    klass.class_eval{|klass|
      klass.first.attributes.each{|k ,v|
        pretty_hash[k.to_sym] =
          [
            PrettyAssociationInspect.value_convert(k, v, klass),
            PrettyAssociationInspect.jp_scripe(klass.human_attribute_name(k)),
            v
          ].compact.join(' | ')
      }
    }
  rescue => e
    ap e
  end
  ap "-"*100;
  ap "#{klass.name} #{jp_scripe(klass.model_name.human)}"
  ap "[クラスメソッド]"
  base_pattern   = "(before|after|around)_(add|remove|restore)|_associated_records_for_|inherited"
  extr_pattern   = "attribute_type_decorations|soft_de|_restore_callback|indexed_|_by_resource"
  delete_pattern = Regexp.new( [ base_pattern, extr_pattern ].join('|') )
  class_m  = model.methods(false) - model.instance_methods
  ap (class_m).delete_if{|name|
    delete_pattern.match(name) }.sort
  ap "[インスタンスメソッド]"
  instance_m = model.instance_methods(false) - model.superclass.instance_methods
  ap (instance_m).delete_if{|name|
    delete_pattern.match(name) }.sort
  ap "[バリデーション]"
  ap model.validators.map{|m|
    m.class.name.gsub(/Active|Record|Validations|Model|Validator|::/,"")
      .concat(" #{m.attributes.join(', ')} #{m.options}") }.sort.uniq
  ap "[アソシエーション]"
  ap associations_hash
  ap "[詳細]"
  ap pretty_hash
  ap "-"*100
end
value_convert(k, v, klass) click to toggle source

バリューを整形

# File lib/pretty_association_inspect.rb, line 147
def value_convert(k, v, klass)
  klass.class_eval {
    return columns_hash[k.to_s].type if v.blank?
    is_e  = Object.const_defined?(:Enumerize) && first.send(k).kind_of?(Enumerize::Value)
    return "#{v} #{first.send(k).text} #{send(k).values} #{send(k).values.map(&:text)}" if is_e
    return v.strftime("%y年%m月%d日 %H:%M") if v.respond_to?(:strftime)
  }
end