diff --git a/lib/rubyzen/collections/classes_collection.rb b/lib/rubyzen/collections/classes_collection.rb index 5d3bcb4..b04c4a6 100644 --- a/lib/rubyzen/collections/classes_collection.rb +++ b/lib/rubyzen/collections/classes_collection.rb @@ -1,11 +1,8 @@ - module Rubyzen module Collections class ClassesCollection < BaseCollection include Rubyzen::Providers::CollectionFilterProvider - undef_method(:methods) - def all_methods instance_plus_class_methods = flat_map { |klass| klass.instance_methods + klass.class_methods } MethodsCollection.new(instance_plus_class_methods) @@ -16,10 +13,19 @@ def attributes AttributesCollection.new(all_attributes) end + def macros + all_macros = flat_map(&:macros) + MacrosCollection.new(all_macros) + end + def with_parent_prefix(prefix) filter { |klass| klass.superclass_prefix?(prefix) } end + def with_macro_name(macro_name) + filter { |klass| klass.macros.with_name(macro_name).any? } + end + def +(other) merged = super(other) self.class.new(merged) diff --git a/lib/rubyzen/collections/macros_collection.rb b/lib/rubyzen/collections/macros_collection.rb new file mode 100644 index 0000000..c59d4e0 --- /dev/null +++ b/lib/rubyzen/collections/macros_collection.rb @@ -0,0 +1,7 @@ +module Rubyzen + module Collections + class MacrosCollection < BaseCollection + include Rubyzen::Providers::CollectionFilterProvider + end + end +end diff --git a/lib/rubyzen/declarations/class_declaration.rb b/lib/rubyzen/declarations/class_declaration.rb index 16d213f..390c442 100644 --- a/lib/rubyzen/declarations/class_declaration.rb +++ b/lib/rubyzen/declarations/class_declaration.rb @@ -9,6 +9,7 @@ class ClassDeclaration include Rubyzen::Providers::ClassNameProvider include Rubyzen::Providers::ConstantsProvider include Rubyzen::Providers::AttributesProvider + include Rubyzen::Providers::MacrosProvider attr_reader :node, :file_declaration diff --git a/lib/rubyzen/declarations/macro_declaration.rb b/lib/rubyzen/declarations/macro_declaration.rb new file mode 100644 index 0000000..a2c419b --- /dev/null +++ b/lib/rubyzen/declarations/macro_declaration.rb @@ -0,0 +1,52 @@ +module Rubyzen + module Declarations + class MacroDeclaration + include Rubyzen::Providers::FilePathProvider + include Rubyzen::Providers::ClassNameProvider + include Rubyzen::Providers::LineNumberProvider + include Rubyzen::Providers::SourceCodeProvider + + attr_reader :node, :parent + + def initialize(node, parent) + @node = node + @parent = parent + end + + def name + node.method_name.to_s + end + + def symbols + node.arguments.select { |arg| arg.type == :sym }.map(&:value) + end + + def strings + node.arguments.select { |arg| arg.type == :str }.map(&:value) + end + + def keyword_args + extract_keyword_args(node) + end + + def receiver + node.receiver&.type == :const ? node.receiver.const_name : nil + end + + private + + def extract_keyword_args(send_node) + send_node.arguments.flat_map do |arg| + if arg.hash_type? + arg.each_pair.map do |pair| + key_node = pair.key + key_node.type == :sym ? key_node.value : nil + end.compact + else + [] + end + end.uniq + end + end + end +end diff --git a/lib/rubyzen/providers/collection_filter_provider.rb b/lib/rubyzen/providers/collection_filter_provider.rb index 59f1abe..0a79a79 100644 --- a/lib/rubyzen/providers/collection_filter_provider.rb +++ b/lib/rubyzen/providers/collection_filter_provider.rb @@ -13,6 +13,14 @@ def with_name_starting_with(prefix) filter { |item| item.name&.start_with?(prefix) } end + def with_name_including(substring, case_sensitive: true) + if case_sensitive + filter { |item| item.name&.include?(substring) } + else + filter { |item| item.name&.downcase&.include?(substring.downcase) } + end + end + def without_name(*names) filter { |item| !names.include?(item.name) } end @@ -24,6 +32,14 @@ def without_name_ending_with(suffix) def without_name_starting_with(prefix) filter { |item| !item.name&.start_with?(prefix) } end + + def without_name_including(substring, case_sensitive: true) + if case_sensitive + filter { |item| !item.name&.include?(substring) } + else + filter { |item| !item.name&.downcase&.include?(substring.downcase) } + end + end end end end diff --git a/lib/rubyzen/providers/macros_provider.rb b/lib/rubyzen/providers/macros_provider.rb new file mode 100644 index 0000000..46e8b1c --- /dev/null +++ b/lib/rubyzen/providers/macros_provider.rb @@ -0,0 +1,15 @@ +module Rubyzen + module Providers + module MacrosProvider + def macros + macros_nodes = node.each_descendant(:send).select(&:macro?) + + macros_declarations = macros_nodes.map do |macro_node| + Rubyzen::Declarations::MacroDeclaration.new(macro_node, self) + end + + Rubyzen::Collections::MacrosCollection.new(macros_declarations) + end + end + end +end diff --git a/sample_project/spec/requests/validate_required_profile_id_lint_spec.rb b/sample_project/spec/requests/validate_required_profile_id_lint_spec.rb new file mode 100644 index 0000000..ef5d193 --- /dev/null +++ b/sample_project/spec/requests/validate_required_profile_id_lint_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require_relative '../spec_helper' + +RSpec.describe 'Requests validate required profile id' do + context 'given a request that uses validates_required' do + it 'validates required profile id' do + expect(requests.with_macro_name('validates_required')).to be_true { |klass| + klass.macros.with_name('validates_required').any? do |macro| + macro.symbols.include?(:profile_id) + end + } + end + end +end diff --git a/sample_project/spec/spec_helper.rb b/sample_project/spec/spec_helper.rb index 8dcef2f..0a88b31 100644 --- a/sample_project/spec/spec_helper.rb +++ b/sample_project/spec/spec_helper.rb @@ -14,6 +14,7 @@ let(:actions) { project.files.with_paths('src/actions/').classes } let(:services) { project.files.with_paths('src/services/').classes } let(:jobs) { project.files.with_paths('src/jobs/').classes } + let(:requests) { project.files.with_paths('src/requests/').classes } let(:models_files) { project.files.with_paths('src/models/') } let(:models) { models_files.classes } diff --git a/sample_project/src/requests/age_verification.rb b/sample_project/src/requests/age_verification.rb new file mode 100644 index 0000000..83a4460 --- /dev/null +++ b/sample_project/src/requests/age_verification.rb @@ -0,0 +1,14 @@ +module Requests + module AgeVerification + class Result < Base::Request + extracts :device_id, :profile_id, :session_id + + validates device_id: Validators::Devices::DeviceId, + profile_id: Validators::Profiles::Id + + validates_required :session_id + + returns :profile_id, :session_id + end + end +end \ No newline at end of file diff --git a/sample_project/src/requests/photo.rb b/sample_project/src/requests/photo.rb new file mode 100644 index 0000000..61d5211 --- /dev/null +++ b/sample_project/src/requests/photo.rb @@ -0,0 +1,13 @@ +module Requests + module Photo + class Result < Base::Request + extracts :device_id, :profile_id, :photo_id + + validates device_id: Validators::Devices::DeviceId + + validates_required :photo_id, :profile_id + + returns :profile_id + end + end +end \ No newline at end of file