module Refinery::ExtensionGeneration

Public Class Methods

included(base) click to toggle source
# File lib/refinery/extension_generation.rb, line 4
def self.included(base)
  base.class_eval do
    argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"

    class_option :namespace, :type => :string, :default => nil, :banner => 'NAMESPACE', :required => false
    class_option :authors, :type => :array, :default => [], :banner => 'author author', :required => false, :desc => 'Indicates authors of this extension'
    class_option :extension, :type => :string, :default => nil, :banner => 'ENGINE', :required => false
    class_option :i18n, :type => :array, :default => [], :required => false, :banner => "field field", :desc => 'Indicates generated fields'
    class_option :install, :type => :boolean, :default => false, :required => false, :banner => nil, :desc => 'Bundles and runs the generated generator, rake db:migrate, rake db:seed for you'

    remove_class_option :skip_namespace
  end
end

Public Instance Methods

attributes_for_translation_table() click to toggle source
# File lib/refinery/extension_generation.rb, line 71
def attributes_for_translation_table
  localized_attributes.inject([]) { |memo, attr| memo << ":#{attr.name} => :#{attr.type}"}.join(', ')
end
extension_authors() click to toggle source
# File lib/refinery/extension_generation.rb, line 37
def extension_authors
  @extension_authors ||= options[:authors].presence
end
extension_class_name() click to toggle source
# File lib/refinery/extension_generation.rb, line 41
def extension_class_name
  @extension_class_name ||= extension_name.camelize
end
extension_name() click to toggle source
# File lib/refinery/extension_generation.rb, line 33
def extension_name
  @extension_name ||= options[:extension].presence || singular_name
end
extension_plural_class_name() click to toggle source
# File lib/refinery/extension_generation.rb, line 45
def extension_plural_class_name
  @extension_plural_class_name ||= if options[:extension].present?
    # Use exactly what the user requested, not a plural version.
    extension_class_name
  else
    extension_class_name.pluralize
  end
end
extension_plural_name() click to toggle source
# File lib/refinery/extension_generation.rb, line 54
def extension_plural_name
  @extension_plural_name ||= if options[:extension].present?
    # Use exactly what the user requested, not a plural version.
    extension_name
  else
    extension_name.pluralize
  end
end
image_attributes() click to toggle source
# File lib/refinery/extension_generation.rb, line 79
def image_attributes
  @image_attributes ||= attributes.select { |a| a.refinery_type == :image }.uniq
end
localized?() click to toggle source
# File lib/refinery/extension_generation.rb, line 63
def localized?
  localized_attributes.any?
end
localized_attributes() click to toggle source
# File lib/refinery/extension_generation.rb, line 67
def localized_attributes
  @localized_attributes ||= attributes.select{ |a| options[:i18n].include?(a.name)}
end
namespacing() click to toggle source
# File lib/refinery/extension_generation.rb, line 18
def namespacing
  @namespacing ||= if options[:namespace].present?
    # Use exactly what the user requested, not a pluralised version.
    options[:namespace].to_s.camelize
  else
    # If the user has passed an engine, we want to generate it inside of
    # that extension.
    if options[:extension].present?
      options[:extension].to_s.camelize
    else
      class_name.pluralize
    end
  end
end
resource_attributes() click to toggle source
# File lib/refinery/extension_generation.rb, line 83
def resource_attributes
  @resource_attributes ||= attributes.select { |a| a.refinery_type == :resource }.uniq
end
string_attributes() click to toggle source
# File lib/refinery/extension_generation.rb, line 75
def string_attributes
  @string_attributes ||= attributes.select { |a| /string|text/ === a.refinery_type.to_s}.uniq
end

Protected Instance Methods

append_extension_to_gemfile!() click to toggle source
# File lib/refinery/extension_generation.rb, line 89
def append_extension_to_gemfile!
  unless Rails.env.test? || (self.behavior != :revoke && extension_in_gemfile?)
    path = extension_pathname.parent.relative_path_from(gemfile.parent)
    append_file gemfile, "\ngem '#{gem_name}', path: '#{path}'"
  end
end
clash_keywords() click to toggle source
# File lib/refinery/extension_generation.rb, line 96
def clash_keywords
  @clash_keywords ||= begin
    clash_keywords = []
    unless (clash_file = source_pathname.parent.join('clash_keywords.yml')).file?
      clash_file = source_pathname.parent.parent.join('clash_keywords.yml')
    end
    clash_keywords = YAML.load_file(clash_file) if clash_file.file?
    clash_keywords
  end
end
copy_or_merge_seeds!() click to toggle source
# File lib/refinery/extension_generation.rb, line 226
def copy_or_merge_seeds!
  FileMerger.new(self, source_seed_file, destination_seed_file).call
end
default_generate!() click to toggle source
# File lib/refinery/extension_generation.rb, line 107
def default_generate!
  sanity_check!

  evaluate_templates!

  unless options[:pretend]
    merge_existing_files! if existing_extension?

    copy_or_merge_seeds! if self.behavior != :revoke

    append_extension_to_gemfile!
  end

  install! if options[:install]

  finalize_extension!
end
destination_pathname() click to toggle source
# File lib/refinery/extension_generation.rb, line 125
def destination_pathname
  @destination_pathname ||= Pathname.new(self.destination_root.to_s)
end
erase_destination!() click to toggle source
# File lib/refinery/extension_generation.rb, line 150
def erase_destination!
  if Pathname.glob(extension_pathname.join('**', '*')).all?(&:directory?)
    say_status :remove, relative_to_original_destination_root(extension_pathname.to_s), true
    FileUtils.rm_rf extension_pathname unless options[:pretend]
  end
end
evaluate_templates!() click to toggle source
# File lib/refinery/extension_generation.rb, line 157
def evaluate_templates!
  viable_templates.each do |source_path, destination_path|
    next if /seeds.rb.erb/ === source_path.to_s && self.behavior != :revoke

    destination_path.sub!('.erb', '') if source_path.to_s !~ /views/

    template source_path, destination_path
  end
end
existing_extension?() click to toggle source
# File lib/refinery/extension_generation.rb, line 167
def existing_extension?
  options[:extension].present? && extension_pathname.directory?
end
exit_with_message!(message) click to toggle source
# File lib/refinery/extension_generation.rb, line 171
def exit_with_message!(message)
  STDERR.puts "\n#{message}\n\n"
  exit 1
end
extension_in_gemfile?() click to toggle source
# File lib/refinery/extension_generation.rb, line 176
def extension_in_gemfile?
  gemfile.read.scan(%r{#{gem_name}}).any?
end
extension_path_for(path, extension, apply_tmp = true) click to toggle source
# File lib/refinery/extension_generation.rb, line 133
def extension_path_for(path, extension, apply_tmp = true)
  path = extension_pathname.join path.sub(%r{#{source_pathname}/?}, '')
  path = substitute_path_placeholders path

  if options[:namespace].present? || options[:extension].present?
    path = increment_migration_timestamp(path)

    # Detect whether this is a special file that needs to get merged not overwritten.
    # This is important only when nesting extensions.
    # Routes and #{gem_name}\.rb have an .erb extension as path points to the generator template
    # We have to exclude it when checking if the file already exists and include it in the regexps
    path = extension_path_for_nested_extension(path, apply_tmp) if options[:extension].present?
  end

  path
end
extension_pathname() click to toggle source
# File lib/refinery/extension_generation.rb, line 129
def extension_pathname
  destination_pathname.join('vendor', 'extensions', extension_plural_name)
end
finalize_extension!() click to toggle source
# File lib/refinery/extension_generation.rb, line 180
def finalize_extension!
  if self.behavior != :revoke && !options[:pretend]
    instruct_user!
  else
    erase_destination!
  end
end
gem_name() click to toggle source
# File lib/refinery/extension_generation.rb, line 188
def gem_name
  "refinerycms-#{extension_plural_name}"
end
gemfile() click to toggle source
# File lib/refinery/extension_generation.rb, line 192
def gemfile
  @gemfile ||= begin
    Bundler.default_gemfile || destination_pathname.join('Gemfile')
  end
end
generator_command() click to toggle source
# File lib/refinery/extension_generation.rb, line 198
def generator_command
  raise "You must override the method 'generator_command' in your generator."
end
install!() click to toggle source
# File lib/refinery/extension_generation.rb, line 202
def install!
  run "bundle install"
  run "rails generate refinery:#{extension_plural_name}"
  run "rake db:migrate"
  run "rake db:seed"
end
instruct_user!() click to toggle source
# File lib/refinery/extension_generation.rb, line 230
def instruct_user!
  unless Rails.env.test?
    puts "------------------------"
    if options[:install]
      puts "Your extension has been generated and installed."
    else
      puts "Now run:"
      puts "bundle install"
      puts "rails generate refinery:#{extension_plural_name}"
      puts "rake db:migrate"
      puts "rake db:seed"
    end
    puts "Please restart your rails server."
    puts "------------------------"
  end
end
merge_existing_files!() click to toggle source
# File lib/refinery/extension_generation.rb, line 209
def merge_existing_files!
  # go through all of the temporary files and merge what we need into the current files.
  tmp_directories = []
  globs = %w[config/locales/*.yml config/routes.rb.erb lib/refinerycms-extension_plural_name.rb.erb]
  Pathname.glob(source_pathname.join("{#{globs.join(',')}}"), File::FNM_DOTMATCH).each do |path|
    # get the path to the current tmp file.
    # Both the new and current paths need to strip the .erb portion from the generator template
    new_file_path = extension_path_for(path, extension_name).sub(/\.erb$/, '')
    tmp_directories << new_file_path.split.first
    current_path = extension_path_for(path, extension_name, false).sub(/\.erb$/, '')

    FileMerger.new(self, current_path, new_file_path, :to => current_path, :mode => 'w+').call
  end

  tmp_directories.uniq.each(&:rmtree)
end
reject_file?(file) click to toggle source
# File lib/refinery/extension_generation.rb, line 247
def reject_file?(file)
  !localized? && file.to_s.include?('locale_picker')
end
reject_template?(file) click to toggle source
# File lib/refinery/extension_generation.rb, line 251
def reject_template?(file)
  file.directory? || reject_file?(file)
end
sanity_check!() click to toggle source
# File lib/refinery/extension_generation.rb, line 255
def sanity_check!
  prevent_clashes!
  prevent_uncountability!
  prevent_empty_attributes!
  prevent_invalid_extension!
end
source_pathname() click to toggle source
# File lib/refinery/extension_generation.rb, line 262
def source_pathname
  @source_pathname ||= Pathname.new(self.class.source_root.to_s)
end

Private Instance Methods

all_templates() click to toggle source
# File lib/refinery/extension_generation.rb, line 348
def all_templates
  Pathname.glob source_pathname.join('**', '**')
end
destination_seed_file() click to toggle source
# File lib/refinery/extension_generation.rb, line 325
def destination_seed_file
  destination_pathname.join extension_path_for(source_seed_file.sub('.erb', ''), extension_name)
end
extension_path_for_nested_extension(path, apply_tmp) click to toggle source
# File lib/refinery/extension_generation.rb, line 267
def extension_path_for_nested_extension(path, apply_tmp)
  return nil if !path.sub(/\.erb$/, '').file? &&
                %r{readme.md|(lib/)?#{plural_name}.rb$} === path.to_s

  if apply_tmp && %r{(locales/.*\.yml)|((config/routes|#{gem_name})\.rb\.erb)$} === path.to_s
    path = path.dirname + 'tmp' + path.basename
  end

  path
end
increment_migration_timestamp(path) click to toggle source
# File lib/refinery/extension_generation.rb, line 278
def increment_migration_timestamp(path)
  # Increment the migration file leading number
  # Only relevant for nested or namespaced extensions, where a previous migration exists
  return path unless %r{/migrate/\d+.*\.rb.erb\z} === path.to_s && last_migration_file(path)

  path.sub(%r{\d+_}) { |m| "#{last_migration_file(path).match(%r{migrate/(\d+)_})[1].to_i + 1}_" }
end
last_migration_file(path) click to toggle source
# File lib/refinery/extension_generation.rb, line 286
def last_migration_file(path)
  Dir[destination_pathname.join(path.dirname + '*.rb')].sort.last
end
prevent_clashes!() click to toggle source
# File lib/refinery/extension_generation.rb, line 290
def prevent_clashes!
  if clash_keywords.member?(singular_name.downcase)
    exit_with_message!("Please choose a different name. The generated code would fail for class '#{singular_name}' as it conflicts with a reserved keyword.")
  end
end
prevent_empty_attributes!() click to toggle source
# File lib/refinery/extension_generation.rb, line 307
def prevent_empty_attributes!
  if attributes.empty? && self.behavior != :revoke
    exit_with_message! "You must specify a name and at least one field." \
                       "\nFor help, run: #{generator_command}"
  end
end
prevent_invalid_extension!() click to toggle source
# File lib/refinery/extension_generation.rb, line 314
def prevent_invalid_extension!
  if options[:extension].present? && !extension_pathname.directory?
    exit_with_message! "You can't use '--extension #{options[:extension]}' because an" \
                       " extension with the name '#{options[:extension]}' doesn't exist."
  end
end
prevent_uncountability!() click to toggle source
# File lib/refinery/extension_generation.rb, line 296
def prevent_uncountability!
  if singular_name == plural_name
    message = if singular_name.singularize == singular_name
      "The extension name you specified will not work as the singular name is equal to the plural name."
    else
      "Please specify the singular name '#{singular_name.singularize}' instead of '#{plural_name}'."
    end
    exit_with_message! message
  end
end
source_seed_file() click to toggle source
# File lib/refinery/extension_generation.rb, line 321
def source_seed_file
  source_pathname.join 'db', 'seeds.rb.erb'
end
substitute_path_placeholders(path) click to toggle source
# File lib/refinery/extension_generation.rb, line 329
def substitute_path_placeholders(path)
  Pathname.new path.to_s.gsub('extension_plural_name', extension_plural_name).
                         gsub('plural_name', plural_name).
                         gsub('singular_name', singular_name).
                         gsub('namespace', namespacing.underscore)
end
viable_templates() click to toggle source
# File lib/refinery/extension_generation.rb, line 336
def viable_templates
  @viable_templates ||= begin
    all_templates.reject(&method(:reject_template?)).inject({}) do |hash, path|
      if (destination_path = extension_path_for(path, extension_name)).present?
        hash[path.to_s] = destination_path.to_s
      end

      hash
    end
  end
end