Module: RailsModuleUnification::DependencyExtensions

Defined in:
lib/rails_module_unification/active_support/dependency_extensions.rb

Constant Summary collapse

RESOURCE_SUFFIX_NAMES =
%w(
  Controller
  Serializer
  Operations
  Presenters
  Policy
  Policies
).freeze
RESOURCE_SUFFIXES =

Join all the suffix names together with an “OR” operator

/(#{RESOURCE_SUFFIX_NAMES.join('|')})/
QUALIFIED_NAME_SPLIT =

split on any of the resource suffixes OR the ruby namespace seperator

/::|#{RESOURCE_SUFFIXES}/

Instance Method Summary collapse

Instance Method Details

#load_from_path(file_path, qualified_name, from_mod, const_name) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/rails_module_unification/active_support/dependency_extensions.rb', line 19

def load_from_path(file_path, qualified_name, from_mod, const_name)
  expanded = File.expand_path(file_path)
  expanded.sub!(/\.rb\z/, '')

  if loading.include?(expanded)
    raise "Circular dependency detected while autoloading constant #{qualified_name}"
  else
    require_or_load(expanded, qualified_name)
    unless from_mod.const_defined?(const_name, false)
      raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it"
    end

    return from_mod.const_get(const_name)
  end
end

#load_missing_constant(from_mod, const_name) ⇒ Object

Load the constant named const_name which is missing from from_mod. If it is not possible to load the constant into from_mod, try its parent module using const_missing.



117
118
119
120
121
122
# File 'lib/rails_module_unification/active_support/dependency_extensions.rb', line 117

def load_missing_constant(from_mod, const_name)
  # always default to the actual implementation
  super
rescue LoadError, NameError => e
  load_missing_constant_error(from_mod, const_name, e)
end

#load_missing_constant_error(from_mod, const_name, e) ⇒ Object

the heavy liftign of Rails Module Unification is just adding some additional pathfinding / constat lookup logic when the default (super) can’t find what needs to be found

Parameters:

  • from_mod (Class)
    • parent module / class that const_name may be a part of

  • const_name (Symbol)
    • potential constant to lookup under from_mod

  • e (Exception)
    • exception from previous error



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/rails_module_unification/active_support/dependency_extensions.rb', line 131

def load_missing_constant_error(from_mod, const_name, e)
  # examples
  # - Api::PostsController
  # - PostsController
  qualified_name = qualified_name_for(from_mod, const_name)
  file_path = resource_path_from_qualified_name(qualified_name)

  begin
    return load_from_path(file_path, qualified_name, from_mod, const_name) if file_path
  rescue LoadError, NameError => e
    # Recurse!
    # not found, check the parent
    at_the_top = from_mod.parent == from_mod
    return load_missing_constant_error(from_mod.parent, const_name, e) unless at_the_top
    raise e
  end

  name_error = NameError.new(e.message)
  name_error.set_backtrace(caller.reject { |l| l.starts_with? __FILE__ })
  raise name_error
end

#resource_path_from_qualified_name(qualified_name) ⇒ Object

Note:

The Lookup Rules:

  • all resources are plural

  • file_names can either be named after the type or traditional ruby/rails nameing i.e.: posts_controller.rb vs controller.rb

  • regular namespacing still applies. i.e: Api::V2::CategoriesController should be in

    api/v2/categories/controller.rb
    
Note:

The Pattern:

  • namespace_a - api

    • namespace_b - v2

      • resource_name (plural) - posts

        • file_type.rb - controller.rb (or posts_controller.rb)

          - operations.rb (or post_operations.rb)
          
        • folder_type - operations/ (or post_operations/)

          • related namespaced classes - create.rb

A look for the possible places that various qualified names could be

All examples assume default resource directory (“resources”) and show the order of lookup

Examples:

Api::PostsController

Possible Locations
 - api/posts/controller.rb
 - api/posts/posts_controller.rb

Api::PostSerializer

Possible Locations
 - api/posts/serializer.rb
 - api/posts/post_serializer.rb

Api::PostOperations::Create

Possible Locations
 - api/posts/operations/create.rb
 - api/posts/post_operations/create.rb

Api::V2::CategoriesController

Possible Locations
 - api/v2/categories/controller.rb
 - api/v2/categories/categories_controller.rb

Parameters:

  • qualified_name (String)

    fully qualified class/module name to find the file location for



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rails_module_unification/active_support/dependency_extensions.rb', line 78

def resource_path_from_qualified_name(qualified_name)
  namespace,
  resource_name,
  resource_type, named_resource_type,
  class_path = ResourceParts.from_name(qualified_name)

  # build all the possible places that this file could be
  path_options = [

    # api/v2/posts/operations/update
    to_path(namespace, resource_name, resource_type, class_path),

    # api/v2/posts/post_operations/update
    to_path(namespace, resource_name, named_resource_type, class_path),

    # api/v2/posts/posts_controller
    to_path(namespace, resource_name, named_resource_type),

    # api/v2/posts/controller
    to_path(namespace, resource_name, resource_type)
  ].uniq

  file_path = ''
  path_options.each do |path_option|
    file_path = search_for_file(path_option)

    break if file_path.present?
  end

  file_path
end

#to_path(*args) ⇒ Object



110
111
112
# File 'lib/rails_module_unification/active_support/dependency_extensions.rb', line 110

def to_path(*args)
  args.flatten.reject(&:blank?).map(&:underscore).join('/')
end