class ADSL::Extract::Rails::RailsExtractor
Attributes
actions[RW]
ar_classes[RW]
instrumentation_filters[RW]
invariants[RW]
Public Class Methods
new(options = {})
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 20 def initialize(options = {}) options = Hash[ :ar_classes => default_activerecord_models, :invariants => Dir['invariants/**/*_invs.rb'], :instrumentation_filters => [] ].merge options @ar_classes = options[:ar_classes].map do |ar_class| generator = ActiveRecordMetaclassGenerator.new ar_class generator.generate_class end ar_class_names = @ar_classes.map(&:adsl_ast_class_name) @invariant_extractor = ADSL::Extract::Rails::InvariantExtractor.new ar_class_names @invariants = @invariant_extractor.extract(options[:invariants]).map{ |inv| inv.adsl_ast } @instrumentation_filters = @invariant_extractor.instrumentation_filters @instrumentation_filters += options[:instrumentation_filters] @action_instrumenter = ADSL::Extract::Rails::ActionInstrumenter.new ar_class_names @action_instrumenter.instrumentation_filters = @instrumentation_filters @actions = [] all_routes.each do |route| translation = action_to_adsl_ast(route) @actions << translation unless translation.nil? end end
Public Instance Methods
action_name_for(route)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 71 def action_name_for(route) "#{route[:controller]}__#{route[:action]}" end
action_of(route)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 182 def action_of(route) return nil unless route.defaults.include? :action route.defaults[:action].to_sym end
action_to_adsl_ast(route)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 101 def action_to_adsl_ast(route) instrumentation_allows = @instrumentation_filters.map do |f| f.allow_instrumentation? route[:controller].new, route[:action] end return nil if instrumentation_allows.include? false action_name = action_name_for route potential_adsl_asts = @actions.select{ |action| action.name.text == action_name } raise "Multiple actions with identical names" if potential_adsl_asts.length > 1 return potential_adsl_asts.first if potential_adsl_asts.length == 1 prepare_instrumentation route[:controller], route[:action] session = ActionDispatch::Integration::Session.new(::Rails.application) ::Rails.application.config.action_dispatch.show_exceptions = false block = @action_instrumenter.exec_within do @action_instrumenter.exec_within do request_method = route[:request_method].to_s.downcase.split('|').first session.send request_method, route[:url] end @action_instrumenter.abb.root_lvl_adsl_ast end interrupt_callback_chain_on_render block, route[:action] action = ADSL::Parser::ASTAction.new({ :name => ADSL::Parser::ASTIdent.new(:text => action_name), :arg_cardinalities => [], :arg_names => [], :arg_types => [], :block => block }) action = action.optimize action.prepend_global_variables_by_signatures /^at__.*/, /^atat__.*/ action end
adsl_ast()
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 201 def adsl_ast ADSL::Parser::ASTSpec.new( :classes => @ar_classes.map(&:adsl_ast), :actions => @actions, :invariants => @invariants ) end
all_routes()
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 48 def all_routes ::Rails.application.routes.routes.map{ |route| { :request_method => request_method_for(route), :url => url_for(route), :controller => controller_of(route), :action => action_of(route) } }.select{ |route| !route[:action].nil? && !route[:controller].nil? && !route[:url].nil? && !route[:request_method].nil? && route[:controller].action_methods.include?(route[:action].to_s) }.uniq{ |a| [a[:controller], a[:action]] }.sort{ |a, b| [a[:controller].to_s, a[:action]] <=> [b[:controller].to_s, b[:action]] } end
callbacks(controller)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 75 def callbacks(controller) controller.respond_to?(:_process_action_callbacks) ? controller._process_action_callbacks : [] end
controller_of(route)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 167 def controller_of(route) return nil unless route.defaults.include? :controller possible_names = [ "#{route.defaults[:controller].pluralize}_controller".camelize, "#{route.defaults[:controller]}_controller".camelize, ] possible_names.each do |name| begin return name.constantize rescue NameError end end raise "No controller class found for #{route.defaults}; attempted class names are #{possible_names}" end
default_activerecord_models()
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 141 def default_activerecord_models models_dir = Rails.respond_to?(:root) ? Rails.root.join('app', 'models') : Pathname.new('app/models') classes = Dir[models_dir.join '**', '*.rb'].map{ |path| relative_path = /^#{Regexp.escape models_dir.to_s}\/(.*)\.rb$/.match(path)[1] klass = nil while klass.nil? && !relative_path.empty? begin klass = relative_path.camelize.constantize rescue NameError, LoadError end if klass.nil? relative_path = /^[^\/]+\/(.*)$/.match(relative_path)[1] end end raise "Could not find class corresponding to path #{path}" if klass.nil? klass }.select{ |klass| klass < ActiveRecord::Base } until_no_change(classes) do |classes| all = classes.dup classes.each do |c| all << c.superclass unless classes.include?(c.superclass) || c.superclass == ActiveRecord::Base end all end end
prepare_instrumentation(controller_class, action)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 79 def prepare_instrumentation(controller_class, action) controller_class.class_eval <<-ruby, __FILE__, __LINE__ + 1 def default_render(*args); end def verify_authenticity_token; end def params ADSL::Extract::Rails::PartiallyUnknownHash.new( :controller => '#{ controller_class.controller_name }', :action => '#{ action }' ) end ruby instrument_gems controller_class, action controller = controller_class.new @action_instrumenter.instrument controller, action callbacks(controller_class).each do |callback| next if callback.filter.is_a?(String) @action_instrumenter.instrument controller, callback.filter end end
request_method_for(route)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 187 def request_method_for(route) method_s = route.verb.source.match(/^\^?(.*?)\$?$/)[1] return nil if method_s.empty? method_s.to_sym end
route_for(controller, action)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 67 def route_for(controller, action) all_routes.select{ |a| a[:controller] == controller && a[:action] == action.to_sym}.first end
url_for(route)
click to toggle source
# File lib/adsl/extract/rails/rails_extractor.rb, line 193 def url_for(route) params = {} route.required_parts.each do |part| params[part] = 0 end route.format(params) end