Skip to content

Instantly share code, notes, and snippets.

@iftheshoefritz
Created June 29, 2020 06:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iftheshoefritz/d9f447e5dad81c864c00f8f1654c0428 to your computer and use it in GitHub Desktop.
Save iftheshoefritz/d9f447e5dad81c864c00f8f1654c0428 to your computer and use it in GitHub Desktop.
namespace :solargraph do
task generate: :environment do
# Add the folder you choose in your config/application.rb
# example:
# config.autoload_paths << Rails.root.join('app/solargraph')
gen_directory = Rails.root.join("config", ".yard")
# run the script as a rails runner:
# jundle exec rails r ./bin/generate_solar_models.rb
# if you wanted to choose specific models to generate for
# models = [User]
Rails.application.eager_load!
models = ApplicationRecord.descendants
puts("generating for #{models.count} models")
models.each do |model|
puts "processing #{model.name}."
columns = model.columns.map do |col|
type = type_translation[col.type]
<<-TXT
# @!attribute #{col.name}
# @return [#{type}]
TXT
end
reflections = model.reflections.map do |key, reflection|
type = reflection_comment(reflection)
puts "KEY: #{key} TYPE: #{type}"
next if type.nil?
<<-TXT
# @!attribute #{key}
# @return #{type}
TXT
end
generated_attributes = <<~TXT
class #{model.name}
#{reflections.join("\n")}
#{columns.join("\n")}
end
TXT
path = gen_directory.join("#{model.model_name.singular}_attrs.rb")
File.write(path, generated_attributes)
puts("written : #{path}")
end
end
def type_translation
{
decimal: "Decimal",
integer: "Int",
date: "Date",
datetime: "DateTime",
string: "String",
boolean: "Bool"
}
end
def class_for(name)
name = name.to_s
found = ApplicationRecord.descendants.detect do |model|
model.model_name.plural == name || model.model_name.singular == name
end
found&.first&.model_name&.name
end
def reflection_type(reflection)
puts "Reflecting with #{reflection}"
case reflection
when ActiveRecord::Reflection::HasManyReflection
:many
when ActiveRecord::Reflection::HasAndBelongsToManyReflection
:many
when ActiveRecord::Reflection::HasOneReflection
:one
when ActiveRecord::Reflection::BelongsToReflection
:one
when ActiveRecord::Reflection::ThroughReflection
reflection_type(reflection.through_reflection)
else
puts("# cannot infer association for #{reflection.name} -> #{reflection.class}")
nil
end
end
def reflection_class_name(reflection)
case reflection
when ActiveRecord::Reflection::HasManyReflection
class_name =
if reflection.options[:class_name].present?
reflection.options[:class_name]
else
class_for(reflection.name)
end
class_name
when ActiveRecord::Reflection::ThroughReflection
class_name =
if reflection.options[:class_name].present?
reflection.options[:class_name]
else
class_for(reflection.name)
end
class_name
when ActiveRecord::Reflection::HasAndBelongsToManyReflection
class_name =
if reflection.options[:class_name].present?
reflection.options[:class_name]
else
class_for(reflection.name)
end
class_name
when ActiveRecord::Reflection::HasOneReflection
reflection.name.to_s.capitalize
when ActiveRecord::Reflection::BelongsToReflection
reflection.name.to_s.capitalize
else
puts("# cannot infer association for #{reflection.name} -> #{reflection.class}")
nil
end
end
def reflection_comment(reflection)
case reflection_type(reflection)
when :one
"[#{reflection_class_name(reflection)}]"
when :many
"[Array<#{reflection_class_name(reflection)}>]"
end
end
end
@iftheshoefritz
Copy link
Author

Thanks to @hellola for the original, just cleaning up some bugs in that: https://gist.github.com/hellola/b832cff599f67a5e353e6af4914d467a

@iftheshoefritz
Copy link
Author

(lots of duplicate code to sort out)

@julianrubisch
Copy link

FWIW, I think you're missing a

      FileUtils.mkdir_p File.dirname(path)

after line 45

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment