rails-annotate-solargraph 0.2.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.vscode/settings.json +5 -0
- data/CHANGELOG.md +18 -0
- data/Gemfile.lock +3 -1
- data/README.md +22 -2
- data/lib/generators/annotate/solargraph/install_generator.rb +16 -0
- data/lib/generators/annotate/solargraph/templates/.annotate_solargraph_schema +69 -0
- data/lib/generators/annotate/solargraph/templates/rails_annotate_solargraph.rake +1 -0
- data/lib/rails/annotate/solargraph/configuration.rb +6 -2
- data/lib/rails/annotate/solargraph/model.rb +197 -52
- data/lib/rails/annotate/solargraph/version.rb +1 -1
- data/lib/rails/annotate/solargraph.rb +17 -0
- data/rails-annotate-solargraph.gemspec +3 -1
- metadata +32 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 641aad34ff5a1a7f98a1eca52baf74c311308b2e9e062cf8c5ac3c0186d1f1ec
         | 
| 4 | 
            +
              data.tar.gz: 70657a49775862f8b50dc2e04f7b489b04f124cbfb4893f777f5a11f69b0ba51
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8a2c58e2d0dbb0dd0df66d1f2f04242095081c4159059c8830021cc16f9ece5222dc9fee73392757b88cf1798f5e53256a09fc2291585b8474c36db8777d64f2
         | 
| 7 | 
            +
              data.tar.gz: 6335dab053b82ff232fdcc69c3453eea68ae44432bd6f4032f29ab812072e9053795955556f14578479bd47ebd37a3bfc6ac592254de63801d38369834dcc358
         | 
    
        data/.vscode/settings.json
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,21 @@ | |
| 1 1 | 
             
            ## [Unreleased]
         | 
| 2 2 |  | 
| 3 | 
            +
            ## [0.5.0] - 2022-04-19
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            - Add some static comments to the schema file to improve general Rails intellisense
         | 
| 6 | 
            +
            - Rename schema file from `app/models/annotate_solargraph_schema.rb` to `.annotate-solargraph-schema`
         | 
| 7 | 
            +
            - Generate schema file as a regular ruby file
         | 
| 8 | 
            +
            - Add `yard` and `solargraph` as dependencies
         | 
| 9 | 
            +
            - Add `.solargraph.yml` to the installation generator
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ## [0.4.0] - 2022-04-17
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            - Annotations get saved to a schema file by default `app/models/annotate_solargraph_schema.rb`
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ## [0.3.0] - 2022-04-17
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            - `has_many :through` and `has_one :through` relations get documented
         | 
| 18 | 
            +
             | 
| 3 19 | 
             
            ## [0.2.3] - 2022-04-16
         | 
| 4 20 |  | 
| 5 21 | 
             
            - A nicer fix for the previous problem
         | 
| @@ -15,6 +31,7 @@ | |
| 15 31 | 
             
            ## [0.2.0] - 2022-04-16
         | 
| 16 32 |  | 
| 17 33 | 
             
            - Associations get fully documented
         | 
| 34 | 
            +
            - `has_many`, `has_one` and `belongs_to` relations get documented
         | 
| 18 35 |  | 
| 19 36 | 
             
            ## [0.1.1] - 2022-04-15
         | 
| 20 37 |  | 
| @@ -24,4 +41,5 @@ | |
| 24 41 |  | 
| 25 42 | 
             
            - Initial release
         | 
| 26 43 | 
             
            - Automatic generation of annotations after migrations
         | 
| 44 | 
            +
            - Database fields get documented
         | 
| 27 45 | 
             
            - Manual rake tasks `annotate:solargraph:generate`, `annotate:solargraph:remove`
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -63,11 +63,31 @@ You can change the gem's default configuration like so: | |
| 63 63 | 
             
            ```ruby
         | 
| 64 64 | 
             
            # config/initializers/rails_annotate_solargraph.rb
         | 
| 65 65 |  | 
| 66 | 
            -
            Rails | 
| 67 | 
            -
                 | 
| 66 | 
            +
            if ::Rails.env.development?
         | 
| 67 | 
            +
                ::Rails::Annotate::Solargraph.configure do |conf|
         | 
| 68 | 
            +
                    conf.annotation_position = :top # `:schema_file` by default
         | 
| 69 | 
            +
                end
         | 
| 68 70 | 
             
            end
         | 
| 69 71 | 
             
            ```
         | 
| 70 72 |  | 
| 73 | 
            +
            #### annotation_position
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            There are a few values for this option:
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            - `:schema_file` -- default value, annotations get saved to a special file `app/models/annotate_solargraph_schema.rb`
         | 
| 78 | 
            +
            - `:bottom` -- annotations are appended to the model files
         | 
| 79 | 
            +
            - `:top` -- annotations are prepended to the model files
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            ### Update
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            To update this gem you should generate the rakefiles once again. Overwrite them.
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            ```sh
         | 
| 86 | 
            +
            $ rails g annotate:solargraph:install
         | 
| 87 | 
            +
            $ rake annotate:solargraph:remove
         | 
| 88 | 
            +
            $ rake annotate:solargraph:generate
         | 
| 89 | 
            +
            ```
         | 
| 90 | 
            +
             | 
| 71 91 | 
             
            ## Development
         | 
| 72 92 |  | 
| 73 93 | 
             
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
| @@ -1,3 +1,8 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'yaml'
         | 
| 4 | 
            +
            require 'set'
         | 
| 5 | 
            +
             | 
| 1 6 | 
             
            module Annotate
         | 
| 2 7 | 
             
              module Solargraph
         | 
| 3 8 | 
             
                module Generators
         | 
| @@ -8,6 +13,17 @@ module Annotate | |
| 8 13 | 
             
                    # copy rake tasks
         | 
| 9 14 | 
             
                    def copy_tasks
         | 
| 10 15 | 
             
                      template ::Rails::Annotate::Solargraph::RAKEFILE_NAME, ::File.join('lib', 'tasks', ::Rails::Annotate::Solargraph::RAKEFILE_NAME)
         | 
| 16 | 
            +
                      template ::Rails::Annotate::Solargraph::SCHEMA_FILE_NAME, ::Rails::Annotate::Solargraph::SCHEMA_RAILS_PATH
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                      solargraph_config_file = ::File.join(::Rails.root, ::Rails::Annotate::Solargraph::SOLARGRAPH_FILE_NAME)
         | 
| 19 | 
            +
                      system 'solargraph config' unless ::File.exist? solargraph_config_file
         | 
| 20 | 
            +
                      solargraph_config = ::YAML.load_file solargraph_config_file
         | 
| 21 | 
            +
                      solargraph_config['include'] = solargraph_config['include'] || []
         | 
| 22 | 
            +
                      solargraph_config['include'].unshift ::Rails::Annotate::Solargraph::SCHEMA_RAILS_PATH
         | 
| 23 | 
            +
                      # make sure there are no duplicated entries
         | 
| 24 | 
            +
                      solargraph_config['include'] = solargraph_config['include'].to_set.to_a
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                      ::File.write(solargraph_config_file, solargraph_config.to_yaml)
         | 
| 11 27 | 
             
                    end
         | 
| 12 28 | 
             
                  end
         | 
| 13 29 | 
             
                end
         | 
| @@ -0,0 +1,69 @@ | |
| 1 | 
            +
            # This is a dummy file generated by `rails-annotate-solargraph`
         | 
| 2 | 
            +
            # to extend solargraph's understanding of your Rails app.
         | 
| 3 | 
            +
            # You should probably add it to `.gitignore`
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            # Some static comments to fill a few gaps
         | 
| 6 | 
            +
            # in Rails comprehension.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class ActionController::Base
         | 
| 9 | 
            +
              include ActionController::MimeResponds
         | 
| 10 | 
            +
              include ActionController::Redirecting
         | 
| 11 | 
            +
              include ActionController::Cookies
         | 
| 12 | 
            +
              include AbstractController::Rendering
         | 
| 13 | 
            +
              extend ActiveSupport::Callbacks::ClassMethods
         | 
| 14 | 
            +
              extend ActiveSupport::Rescuable::ClassMethods
         | 
| 15 | 
            +
              extend AbstractController::Callbacks::ClassMethods
         | 
| 16 | 
            +
              extend ActionController::RequestForgeryProtection::ClassMethods
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
            class ActiveRecord::Base
         | 
| 19 | 
            +
              extend ActiveRecord::Reflection::ClassMethods
         | 
| 20 | 
            +
              extend ActiveModel::SecurePassword::ClassMethods
         | 
| 21 | 
            +
              extend ActiveModel::Attributes::ClassMethods
         | 
| 22 | 
            +
              include ActiveModel::Attributes
         | 
| 23 | 
            +
              include ActiveModel::Dirty
         | 
| 24 | 
            +
              extend ActiveRecord::Validations::ClassMethods
         | 
| 25 | 
            +
              include ActiveRecord::Validations
         | 
| 26 | 
            +
              extend ActiveModel::Validations::ClassMethods
         | 
| 27 | 
            +
              include ActiveModel::Validations
         | 
| 28 | 
            +
              extend ActiveRecord::Calculations
         | 
| 29 | 
            +
              extend ActiveRecord::Batches
         | 
| 30 | 
            +
              extend ActiveRecord::QueryMethods
         | 
| 31 | 
            +
              extend ActiveRecord::FinderMethods
         | 
| 32 | 
            +
              extend ActiveRecord::Associations::ClassMethods
         | 
| 33 | 
            +
              extend ActiveRecord::Inheritance::ClassMethods
         | 
| 34 | 
            +
              extend ActiveRecord::ModelSchema::ClassMethods
         | 
| 35 | 
            +
              extend ActiveRecord::Transactions::ClassMethods
         | 
| 36 | 
            +
              extend ActiveRecord::Scoping::Named::ClassMethods
         | 
| 37 | 
            +
              include ActiveRecord::Persistence
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            <% (ActiveRecord::Callbacks::CALLBACKS rescue []).each do |callback| -%>
         | 
| 40 | 
            +
              # Registers a callback to be called <%= callback.to_s.gsub('_', ' ') %>.
         | 
| 41 | 
            +
              # See `ActiveRecord::Callbacks` for more information.
         | 
| 42 | 
            +
              # @return [void]
         | 
| 43 | 
            +
              def self.<%= callback %>(*args, &block); end
         | 
| 44 | 
            +
            <% end -%>
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            end
         | 
| 47 | 
            +
            class Rails
         | 
| 48 | 
            +
              # @return [Rails::Application]
         | 
| 49 | 
            +
              def self.application; end
         | 
| 50 | 
            +
            end
         | 
| 51 | 
            +
            class Rails::Application
         | 
| 52 | 
            +
              # @return [ActionDispatch::Routing::RouteSet]
         | 
| 53 | 
            +
              def routes; end
         | 
| 54 | 
            +
            end
         | 
| 55 | 
            +
            class ActionDispatch::Routing::Mapper
         | 
| 56 | 
            +
              include ActionDispatch::Routing::Mapper::Base
         | 
| 57 | 
            +
              include ActionDispatch::Routing::Mapper::HttpHelpers
         | 
| 58 | 
            +
              include ActionDispatch::Routing::Mapper::Redirection
         | 
| 59 | 
            +
              include ActionDispatch::Routing::Mapper::Scoping
         | 
| 60 | 
            +
              include ActionDispatch::Routing::Mapper::Concerns
         | 
| 61 | 
            +
              include ActionDispatch::Routing::Mapper::Resources
         | 
| 62 | 
            +
              include ActionDispatch::Routing::Mapper::CustomUrls
         | 
| 63 | 
            +
            end
         | 
| 64 | 
            +
            class ActionDispatch::Routing::RouteSet
         | 
| 65 | 
            +
              # @yieldself [ActionDispatch::Routing::Mapper]
         | 
| 66 | 
            +
              def draw; end
         | 
| 67 | 
            +
            end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            # Dynamically generated documentation
         | 
| @@ -9,10 +9,10 @@ module Rails | |
| 9 9 | 
             
                    # @return [Symbol]
         | 
| 10 10 | 
             
                    attr_reader :annotation_position
         | 
| 11 11 |  | 
| 12 | 
            -
                    ANNOTATION_POSITIONS = ::Set[:bottom, :top].freeze
         | 
| 12 | 
            +
                    ANNOTATION_POSITIONS = ::Set[:bottom, :top, :schema_file].freeze
         | 
| 13 13 |  | 
| 14 14 | 
             
                    def initialize
         | 
| 15 | 
            -
                      @annotation_position = : | 
| 15 | 
            +
                      @annotation_position = :schema_file
         | 
| 16 16 | 
             
                    end
         | 
| 17 17 |  | 
| 18 18 | 
             
                    # @param val [Symbol]
         | 
| @@ -22,6 +22,10 @@ module Rails | |
| 22 22 |  | 
| 23 23 | 
             
                      @annotation_position = val
         | 
| 24 24 | 
             
                    end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    def schema_file?
         | 
| 27 | 
            +
                      @annotation_position == :schema_file
         | 
| 28 | 
            +
                    end
         | 
| 25 29 | 
             
                  end
         | 
| 26 30 | 
             
                end
         | 
| 27 31 | 
             
              end
         | 
| @@ -1,44 +1,55 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'fileutils'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module Rails
         | 
| 4 6 | 
             
              module Annotate
         | 
| 5 7 | 
             
                module Solargraph
         | 
| 6 8 | 
             
                  class Model
         | 
| 7 9 | 
             
                    using TerminalColors::Refinement
         | 
| 8 10 |  | 
| 9 | 
            -
                    # @return [String]
         | 
| 10 | 
            -
                    ANNOTATION_START = "\n# %%<RailsAnnotateSolargraph:Start>%%"
         | 
| 11 | 
            -
                    # @return [String]
         | 
| 12 | 
            -
                    ANNOTATION_END = "%%<RailsAnnotateSolargraph:End>%%\n\n"
         | 
| 13 | 
            -
                    # @return [Regexp]
         | 
| 14 | 
            -
                    ANNOTATION_REGEXP = /#{ANNOTATION_START}.*#{ANNOTATION_END}/m.freeze
         | 
| 15 11 | 
             
                    # @return [Regexp]
         | 
| 16 12 | 
             
                    MAGIC_COMMENT_REGEXP = /(^#\s*encoding:.*(?:\n|r\n))|(^# coding:.*(?:\n|\r\n))|(^# -\*- coding:.*(?:\n|\r\n))|(^# -\*- encoding\s?:.*(?:\n|\r\n))|(^#\s*frozen_string_literal:.+(?:\n|\r\n))|(^# -\*- frozen_string_literal\s*:.+-\*-(?:\n|\r\n))/.freeze
         | 
| 17 13 |  | 
| 14 | 
            +
                    # @return [Hash{Symbol => String}]
         | 
| 15 | 
            +
                    TYPE_MAP = {
         | 
| 16 | 
            +
                      float: 'BigDecimal',
         | 
| 17 | 
            +
                      decimal: 'BigDecimal',
         | 
| 18 | 
            +
                      integer: 'Integer',
         | 
| 19 | 
            +
                      datetime: 'ActiveSupport::TimeWithZone',
         | 
| 20 | 
            +
                      date: 'Date',
         | 
| 21 | 
            +
                      string: 'String',
         | 
| 22 | 
            +
                      boolean: 'Boolean',
         | 
| 23 | 
            +
                      text: 'String',
         | 
| 24 | 
            +
                      jsonb: 'Hash',
         | 
| 25 | 
            +
                      citext: 'String',
         | 
| 26 | 
            +
                      json: 'Hash',
         | 
| 27 | 
            +
                      bigint: 'Integer',
         | 
| 28 | 
            +
                      uuid: 'String',
         | 
| 29 | 
            +
                      inet: 'IPAddr'
         | 
| 30 | 
            +
                    }
         | 
| 31 | 
            +
                    TYPE_MAP.default = 'Object'
         | 
| 32 | 
            +
                    TYPE_MAP.freeze
         | 
| 33 | 
            +
             | 
| 18 34 | 
             
                    class << self
         | 
| 19 | 
            -
                      # @param  | 
| 35 | 
            +
                      # @param klass [Class]
         | 
| 20 36 | 
             
                      # @return [String]
         | 
| 21 | 
            -
                      def  | 
| 22 | 
            -
                         | 
| 23 | 
            -
                         | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
                         | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
                        when :boolean
         | 
| 38 | 
            -
                          'Boolean'
         | 
| 39 | 
            -
                        else
         | 
| 40 | 
            -
                          ::Object.to_s
         | 
| 41 | 
            -
                        end
         | 
| 37 | 
            +
                      def annotation_start(klass = nil)
         | 
| 38 | 
            +
                        table_name = klass && CONFIG.schema_file? ? ":#{klass.table_name}" : ''
         | 
| 39 | 
            +
                        "\n# %%<RailsAnnotateSolargraph:Start#{table_name}>%%"
         | 
| 40 | 
            +
                      end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                      # @param klass [Class]
         | 
| 43 | 
            +
                      # @return [String]
         | 
| 44 | 
            +
                      def annotation_end(klass = nil)
         | 
| 45 | 
            +
                        table_name = klass && CONFIG.schema_file? ? ":#{klass.table_name}" : ''
         | 
| 46 | 
            +
                        "%%<RailsAnnotateSolargraph:End#{table_name}>%%\n\n"
         | 
| 47 | 
            +
                      end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                      # @param klass [Class]
         | 
| 50 | 
            +
                      # @return [Regexp]
         | 
| 51 | 
            +
                      def annotation_regexp(klass = nil)
         | 
| 52 | 
            +
                        /#{annotation_start(klass)}.*#{annotation_end(klass)}/m
         | 
| 42 53 | 
             
                      end
         | 
| 43 54 | 
             
                    end
         | 
| 44 55 |  | 
| @@ -51,7 +62,22 @@ module Rails | |
| 51 62 | 
             
                    # @param klass [Class]
         | 
| 52 63 | 
             
                    def initialize(klass)
         | 
| 53 64 | 
             
                      @klass = klass
         | 
| 54 | 
            -
                      @file_name = ::File.join(::Rails.root, MODEL_DIR, "#{klass.to_s.underscore}.rb")
         | 
| 65 | 
            +
                      @file_name = CONFIG.schema_file? ? SCHEMA_RAILS_PATH : ::File.join(::Rails.root, MODEL_DIR, "#{klass.to_s.underscore}.rb")
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    # @return [String]
         | 
| 69 | 
            +
                    def annotation_start
         | 
| 70 | 
            +
                      self.class.annotation_start(@klass)
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    # @return [String]
         | 
| 74 | 
            +
                    def annotation_end
         | 
| 75 | 
            +
                      self.class.annotation_end(@klass)
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                    # @return [Regexp]
         | 
| 79 | 
            +
                    def annotation_regexp
         | 
| 80 | 
            +
                      self.class.annotation_regexp(@klass)
         | 
| 55 81 | 
             
                    end
         | 
| 56 82 |  | 
| 57 83 | 
             
                    # @param :write [Boolean]
         | 
| @@ -79,8 +105,10 @@ module Rails | |
| 79 105 | 
             
                    # @param :write [Boolean]
         | 
| 80 106 | 
             
                    # @return [Array<String>] Old file content followed by new content.
         | 
| 81 107 | 
             
                    def remove_annotation(write: true)
         | 
| 108 | 
            +
                      return ['', ''] unless ::File.exist?(@file_name)
         | 
| 109 | 
            +
             | 
| 82 110 | 
             
                      file_content = ::File.read(@file_name)
         | 
| 83 | 
            -
                      new_file_content = file_content.sub( | 
| 111 | 
            +
                      new_file_content = file_content.sub(annotation_regexp, '')
         | 
| 84 112 | 
             
                      result = [file_content, new_file_content]
         | 
| 85 113 | 
             
                      return result unless write
         | 
| 86 114 | 
             
                      return result if file_content == new_file_content
         | 
| @@ -93,8 +121,8 @@ module Rails | |
| 93 121 | 
             
                    def annotation
         | 
| 94 122 | 
             
                      doc_string = ::String.new
         | 
| 95 123 | 
             
                      doc_string << <<~DOC
         | 
| 96 | 
            -
                        #{ | 
| 97 | 
            -
                         | 
| 124 | 
            +
                        #{annotation_start}
         | 
| 125 | 
            +
                        ##{parse_clause}
         | 
| 98 126 | 
             
                        #   class #{@klass} < #{@klass.superclass}
         | 
| 99 127 | 
             
                      DOC
         | 
| 100 128 |  | 
| @@ -117,12 +145,23 @@ module Rails | |
| 117 145 |  | 
| 118 146 | 
             
                      doc_string << <<~DOC.chomp
         | 
| 119 147 | 
             
                        #   end
         | 
| 120 | 
            -
                        # #{ | 
| 148 | 
            +
                        # #{annotation_end}
         | 
| 121 149 | 
             
                      DOC
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                      # uncomment the generated annotations if they're saved in the schema file
         | 
| 152 | 
            +
                      return doc_string.gsub(/^#\ {3}/, '').gsub(/^#\n/, "\n") if CONFIG.schema_file?
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                      doc_string
         | 
| 122 155 | 
             
                    end
         | 
| 123 156 |  | 
| 124 157 | 
             
                    private
         | 
| 125 158 |  | 
| 159 | 
            +
                    def parse_clause
         | 
| 160 | 
            +
                      return if CONFIG.schema_file?
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                      " @!parse\n#"
         | 
| 163 | 
            +
                    end
         | 
| 164 | 
            +
             | 
| 126 165 | 
             
                    # @param file_name [String]
         | 
| 127 166 | 
             
                    # @return [String]
         | 
| 128 167 | 
             
                    def relative_file_name(file_name)
         | 
| @@ -133,6 +172,7 @@ module Rails | |
| 133 172 | 
             
                    # @param content [String]
         | 
| 134 173 | 
             
                    # @return [void]
         | 
| 135 174 | 
             
                    def write_file(file_name, content)
         | 
| 175 | 
            +
                      ::FileUtils.touch(file_name) unless ::File.exists?(file_name)
         | 
| 136 176 | 
             
                      ::File.write(file_name, content)
         | 
| 137 177 | 
             
                      puts "modify".rjust(12).with_styles(:bold, :green) + "  #{relative_file_name(file_name)}"
         | 
| 138 178 | 
             
                    end
         | 
| @@ -142,37 +182,57 @@ module Rails | |
| 142 182 | 
             
                      @klass.table_name[..-2]
         | 
| 143 183 | 
             
                    end
         | 
| 144 184 |  | 
| 185 | 
            +
                    # @param reflection [ActiveRecord::Reflection::AbstractReflection]
         | 
| 186 | 
            +
                    # @return [Class]
         | 
| 187 | 
            +
                    def reflection_class(reflection)
         | 
| 188 | 
            +
                      reflection.klass
         | 
| 189 | 
            +
                    rescue ::NameError
         | 
| 190 | 
            +
                      Object
         | 
| 191 | 
            +
                    end
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                    # @param reflection [ActiveRecord::Reflection::AbstractReflection]
         | 
| 194 | 
            +
                    # @return [String]
         | 
| 195 | 
            +
                    def reflection_foreign_key(reflection)
         | 
| 196 | 
            +
                      reflection.try(:foreign_key) || '<unknown>'
         | 
| 197 | 
            +
                    end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                    # @param klass [Class]
         | 
| 200 | 
            +
                    # @return [String]
         | 
| 201 | 
            +
                    def class_table_name(klass)
         | 
| 202 | 
            +
                      klass.try(:table_name) || '<unknown>'
         | 
| 203 | 
            +
                    end
         | 
| 204 | 
            +
             | 
| 145 205 | 
             
                    # @param doc_string [String]
         | 
| 146 206 | 
             
                    # @param attr_name [String]
         | 
| 147 207 | 
             
                    # @param reflection [ActiveRecord::Reflection::AbstractReflection]
         | 
| 148 208 | 
             
                    # @return [void]
         | 
| 149 209 | 
             
                    def document_relation(doc_string, attr_name, reflection)
         | 
| 150 | 
            -
                       | 
| 151 | 
            -
             | 
| 152 | 
            -
                      rescue ::NameError
         | 
| 153 | 
            -
                        Object
         | 
| 154 | 
            -
                      end
         | 
| 155 | 
            -
             | 
| 156 | 
            -
                      associated_table_name = reflection_class.try(:table_name) || '<unknown>'
         | 
| 157 | 
            -
                      foreign_key = reflection.try(:foreign_key) || '<unknown>'
         | 
| 158 | 
            -
                      db_description = \
         | 
| 210 | 
            +
                      reflection_klass = reflection_class(reflection)
         | 
| 211 | 
            +
                      type_docstring, db_description = \
         | 
| 159 212 | 
             
                        case reflection
         | 
| 160 213 | 
             
                        when ::ActiveRecord::Reflection::BelongsToReflection
         | 
| 161 | 
            -
                           | 
| 162 | 
            -
             | 
| 214 | 
            +
                          belongs_to_description(reflection_klass,
         | 
| 215 | 
            +
                                                 class_table_name(@klass),
         | 
| 216 | 
            +
                                                 reflection_foreign_key(reflection))
         | 
| 163 217 | 
             
                        when ::ActiveRecord::Reflection::HasOneReflection
         | 
| 164 | 
            -
                           | 
| 165 | 
            -
             | 
| 218 | 
            +
                          has_one_description(reflection_klass,
         | 
| 219 | 
            +
                                              class_table_name(reflection_klass),
         | 
| 220 | 
            +
                                              reflection_foreign_key(reflection))
         | 
| 166 221 | 
             
                        when ::ActiveRecord::Reflection::HasManyReflection
         | 
| 167 | 
            -
                           | 
| 168 | 
            -
             | 
| 222 | 
            +
                          has_many_description(reflection_klass,
         | 
| 223 | 
            +
                                               class_table_name(reflection_klass),
         | 
| 224 | 
            +
                                               reflection_foreign_key(reflection))
         | 
| 225 | 
            +
                        when ::ActiveRecord::Reflection::ThroughReflection
         | 
| 226 | 
            +
                          through_description(reflection)
         | 
| 227 | 
            +
                        else
         | 
| 228 | 
            +
                          [::Object.to_s, '']
         | 
| 169 229 | 
             
                        end
         | 
| 170 230 |  | 
| 171 231 | 
             
                      doc_string << <<~DOC
         | 
| 172 | 
            -
                        #      | 
| 232 | 
            +
                        #     ##{db_description}
         | 
| 173 233 | 
             
                        #     # @param val [#{type_docstring}, nil]
         | 
| 174 234 | 
             
                        #     def #{attr_name}=(val); end
         | 
| 175 | 
            -
                        #      | 
| 235 | 
            +
                        #     ##{db_description}
         | 
| 176 236 | 
             
                        #     # @return [#{type_docstring}, nil]
         | 
| 177 237 | 
             
                        #     def #{attr_name}; end
         | 
| 178 238 | 
             
                      DOC
         | 
| @@ -187,7 +247,7 @@ module Rails | |
| 187 247 | 
             
                        model_class.reflections[klass_relation_name]&.options&.[](:as)&.to_sym == attr_name.to_sym
         | 
| 188 248 | 
             
                      end
         | 
| 189 249 |  | 
| 190 | 
            -
                      classes_string = classes.join(', ')
         | 
| 250 | 
            +
                      classes_string = classes.empty? ? ::Object.to_s : classes.join(', ')
         | 
| 191 251 | 
             
                      doc_string << <<~DOC
         | 
| 192 252 | 
             
                        #     # Polymorphic relation. Database columns `#{@klass.table_name}.#{attr_name}_id` and `#{@klass.table_name}.#{attr_name}_type`.
         | 
| 193 253 | 
             
                        #     # @param val [#{classes_string}, nil]
         | 
| @@ -198,13 +258,98 @@ module Rails | |
| 198 258 | 
             
                      DOC
         | 
| 199 259 | 
             
                    end
         | 
| 200 260 |  | 
| 261 | 
            +
                    # @param reflection [ActiveRecord::Reflection::AbstractReflection]
         | 
| 262 | 
            +
                    # @return [Array<String>]
         | 
| 263 | 
            +
                    def through_description(reflection)
         | 
| 264 | 
            +
                      through_klass = reflection_class(reflection.through_reflection)
         | 
| 265 | 
            +
             | 
| 266 | 
            +
                      case (reflection.__send__(:delegate_reflection) rescue nil)
         | 
| 267 | 
            +
                      when ::ActiveRecord::Reflection::HasOneReflection
         | 
| 268 | 
            +
                        has_one_description(reflection_class(reflection.source_reflection),
         | 
| 269 | 
            +
                                            class_table_name(through_klass),
         | 
| 270 | 
            +
                                            reflection_foreign_key(reflection.source_reflection),
         | 
| 271 | 
            +
                                            through: through_klass)
         | 
| 272 | 
            +
                      when ::ActiveRecord::Reflection::HasManyReflection
         | 
| 273 | 
            +
                        has_many_description(reflection_class(reflection.source_reflection),
         | 
| 274 | 
            +
                                             class_table_name(through_klass),
         | 
| 275 | 
            +
                                             reflection_foreign_key(reflection.source_reflection),
         | 
| 276 | 
            +
                                             through: through_klass)
         | 
| 277 | 
            +
                      else
         | 
| 278 | 
            +
                        [::Object.to_s, '']
         | 
| 279 | 
            +
                      end
         | 
| 280 | 
            +
                    end
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                    # @param through [Class, nil]
         | 
| 283 | 
            +
                    # @return [String]
         | 
| 284 | 
            +
                    def through_sentence(through = nil)
         | 
| 285 | 
            +
                      return '' unless through
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                      " through `#{through}`"
         | 
| 288 | 
            +
                    end
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                    # @param table_name [String]
         | 
| 291 | 
            +
                    # @param foreign_key [String]
         | 
| 292 | 
            +
                    # @param through [Class, nil]
         | 
| 293 | 
            +
                    # @return [String]
         | 
| 294 | 
            +
                    def column_description(table_name, foreign_key, through = nil)
         | 
| 295 | 
            +
                      return '' if through
         | 
| 296 | 
            +
             | 
| 297 | 
            +
                      " Database column `#{table_name}.#{foreign_key}`."
         | 
| 298 | 
            +
                    end
         | 
| 299 | 
            +
             | 
| 300 | 
            +
                    # @param relation [Symbol, String]
         | 
| 301 | 
            +
                    # @param klass [Class]
         | 
| 302 | 
            +
                    # @param table_name [String]
         | 
| 303 | 
            +
                    # @param foreign_key [String]
         | 
| 304 | 
            +
                    # @param through [Class, nil]
         | 
| 305 | 
            +
                    # @return [String]
         | 
| 306 | 
            +
                    def relation_description(relation, klass, table_name, foreign_key, through = nil)
         | 
| 307 | 
            +
                      " `#{relation}` relation with `#{klass}`#{through_sentence(through)}.#{column_description(table_name, foreign_key, through)}"
         | 
| 308 | 
            +
                    end
         | 
| 309 | 
            +
             | 
| 310 | 
            +
             | 
| 311 | 
            +
                    # @param klass [Class]
         | 
| 312 | 
            +
                    # @param table_name [String]
         | 
| 313 | 
            +
                    # @param foreign_key [String]
         | 
| 314 | 
            +
                    # @param :through [Class, nil]
         | 
| 315 | 
            +
                    # @return [Array<String>] Type docstring followed by the description of the method.
         | 
| 316 | 
            +
                    def has_many_description(klass, table_name, foreign_key, through: nil)
         | 
| 317 | 
            +
                      type_docstring = "Array<#{klass}>"
         | 
| 318 | 
            +
                      desc = relation_description(:has_many, klass, table_name, foreign_key, through)
         | 
| 319 | 
            +
             | 
| 320 | 
            +
                      [type_docstring, desc]
         | 
| 321 | 
            +
                    end
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                    # @param klass [Class]
         | 
| 324 | 
            +
                    # @param table_name [String]
         | 
| 325 | 
            +
                    # @param foreign_key [String]
         | 
| 326 | 
            +
                    # @param :through [Class, nil]
         | 
| 327 | 
            +
                    # @return [Array<String>] Type docstring followed by the description of the method.
         | 
| 328 | 
            +
                    def has_one_description(klass, table_name, foreign_key, through: nil)
         | 
| 329 | 
            +
                      type_docstring = klass
         | 
| 330 | 
            +
                      desc = relation_description(:has_one, klass, table_name, foreign_key, through)
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                      [type_docstring, desc]
         | 
| 333 | 
            +
                    end
         | 
| 334 | 
            +
             | 
| 335 | 
            +
                    # @param klass [Class]
         | 
| 336 | 
            +
                    # @param table_name [String]
         | 
| 337 | 
            +
                    # @param foreign_key [String]
         | 
| 338 | 
            +
                    # @return [Array<String>] Type docstring followed by the description of the method.
         | 
| 339 | 
            +
                    def belongs_to_description(klass, table_name, foreign_key)
         | 
| 340 | 
            +
                      type_docstring = klass
         | 
| 341 | 
            +
                      desc = relation_description(:belongs_to, klass, table_name, foreign_key)
         | 
| 342 | 
            +
             | 
| 343 | 
            +
                      [type_docstring, desc]
         | 
| 344 | 
            +
                    end
         | 
| 345 | 
            +
             | 
| 201 346 | 
             
                    # @param attr_type [ActiveModel::Type::Value]
         | 
| 202 347 | 
             
                    # @return [String]
         | 
| 203 348 | 
             
                    def yard_type(attr_type)
         | 
| 204 349 | 
             
                      return attr_type.coder.object_class.to_s if attr_type.respond_to?(:coder) && attr_type.coder.respond_to?(:object_class)
         | 
| 205 350 | 
             
                      return 'Object' if attr_type.respond_to?(:coder) && attr_type.coder.is_a?(::ActiveRecord::Coders::JSON)
         | 
| 206 351 |  | 
| 207 | 
            -
                       | 
| 352 | 
            +
                      TYPE_MAP[attr_type.type]
         | 
| 208 353 | 
             
                    end
         | 
| 209 354 | 
             
                  end
         | 
| 210 355 | 
             
                end
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require 'set'
         | 
| 4 | 
            +
            require 'fileutils'
         | 
| 4 5 |  | 
| 5 6 | 
             
            require_relative "solargraph/version"
         | 
| 6 7 | 
             
            require_relative "solargraph/configuration"
         | 
| @@ -19,11 +20,20 @@ module Rails | |
| 19 20 | 
             
                  CONFIG = Configuration.new
         | 
| 20 21 | 
             
                  # @return [Set<Symbol>]
         | 
| 21 22 | 
             
                  VALID_MODIFICATION_METHODS = ::Set[:annotate, :remove_annotation].freeze
         | 
| 23 | 
            +
                  # @return [String]
         | 
| 24 | 
            +
                  SCHEMA_CLASS_NAME = 'AnnotateSolargraphSchema'
         | 
| 25 | 
            +
                  # @return [String]
         | 
| 26 | 
            +
                  SOLARGRAPH_FILE_NAME = '.solargraph.yml'
         | 
| 27 | 
            +
                  # @return [String]
         | 
| 28 | 
            +
                  SCHEMA_FILE_NAME = '.annotate_solargraph_schema'
         | 
| 29 | 
            +
                  # @return [String]
         | 
| 30 | 
            +
                  SCHEMA_RAILS_PATH = SCHEMA_FILE_NAME
         | 
| 22 31 |  | 
| 23 32 | 
             
                  class << self
         | 
| 24 33 | 
             
                    # @return [Array<String>] Array of changed files.
         | 
| 25 34 | 
             
                    def generate
         | 
| 26 35 | 
             
                      title 'Generating model schema annotations'
         | 
| 36 | 
            +
                      create_schema_file
         | 
| 27 37 | 
             
                      modify_models :annotate
         | 
| 28 38 | 
             
                    end
         | 
| 29 39 |  | 
| @@ -49,6 +59,13 @@ module Rails | |
| 49 59 |  | 
| 50 60 | 
             
                    include TerminalColors
         | 
| 51 61 |  | 
| 62 | 
            +
                    def create_schema_file
         | 
| 63 | 
            +
                      schema_file = ::File.join ::Rails.root, SCHEMA_RAILS_PATH
         | 
| 64 | 
            +
                      return if ::File.exist?(schema_file)
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                      system 'rails g annotate:solargraph:install'
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
             | 
| 52 69 | 
             
                    # @param method [Symbol] Name of the method that will be called on every loaded Model
         | 
| 53 70 | 
             
                    # @return [Array<String>] Array of changed files.
         | 
| 54 71 | 
             
                    def modify_models(method)
         | 
| @@ -16,7 +16,7 @@ Gem::Specification.new do |spec| | |
| 16 16 |  | 
| 17 17 | 
             
              spec.metadata["homepage_uri"] = spec.homepage
         | 
| 18 18 | 
             
              spec.metadata["source_code_uri"] = "https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph"
         | 
| 19 | 
            -
               | 
| 19 | 
            +
              spec.metadata["changelog_uri"] = "https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph/-/raw/main/CHANGELOG.md"
         | 
| 20 20 |  | 
| 21 21 | 
             
              # Specify which files should be added to the gem when it is released.
         | 
| 22 22 | 
             
              # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
         | 
| @@ -31,6 +31,8 @@ Gem::Specification.new do |spec| | |
| 31 31 |  | 
| 32 32 | 
             
              # Uncomment to register a new dependency of your gem
         | 
| 33 33 | 
             
              spec.add_dependency 'rails', ">= 5.0", '< 8.0'
         | 
| 34 | 
            +
              spec.add_dependency 'solargraph'
         | 
| 35 | 
            +
              spec.add_dependency 'yard'
         | 
| 34 36 |  | 
| 35 37 | 
             
              # For more information and examples about making a new gem, check out our
         | 
| 36 38 | 
             
              # guide at: https://bundler.io/guides/creating_gem.html
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rails-annotate-solargraph
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Mateusz Drewniak
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022-04- | 
| 11 | 
            +
            date: 2022-04-19 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rails
         | 
| @@ -30,6 +30,34 @@ dependencies: | |
| 30 30 | 
             
                - - "<"
         | 
| 31 31 | 
             
                  - !ruby/object:Gem::Version
         | 
| 32 32 | 
             
                    version: '8.0'
         | 
| 33 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 34 | 
            +
              name: solargraph
         | 
| 35 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 36 | 
            +
                requirements:
         | 
| 37 | 
            +
                - - ">="
         | 
| 38 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 39 | 
            +
                    version: '0'
         | 
| 40 | 
            +
              type: :runtime
         | 
| 41 | 
            +
              prerelease: false
         | 
| 42 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 43 | 
            +
                requirements:
         | 
| 44 | 
            +
                - - ">="
         | 
| 45 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 46 | 
            +
                    version: '0'
         | 
| 47 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 48 | 
            +
              name: yard
         | 
| 49 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 50 | 
            +
                requirements:
         | 
| 51 | 
            +
                - - ">="
         | 
| 52 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 53 | 
            +
                    version: '0'
         | 
| 54 | 
            +
              type: :runtime
         | 
| 55 | 
            +
              prerelease: false
         | 
| 56 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 57 | 
            +
                requirements:
         | 
| 58 | 
            +
                - - ">="
         | 
| 59 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 60 | 
            +
                    version: '0'
         | 
| 33 61 | 
             
            description: Annotate ActiveRecord models with schema comments formatted in YARD that
         | 
| 34 62 | 
             
              are compatible with Solargraph.
         | 
| 35 63 | 
             
            email:
         | 
| @@ -53,6 +81,7 @@ files: | |
| 53 81 | 
             
            - bin/console
         | 
| 54 82 | 
             
            - bin/setup
         | 
| 55 83 | 
             
            - lib/generators/annotate/solargraph/install_generator.rb
         | 
| 84 | 
            +
            - lib/generators/annotate/solargraph/templates/.annotate_solargraph_schema
         | 
| 56 85 | 
             
            - lib/generators/annotate/solargraph/templates/rails_annotate_solargraph.rake
         | 
| 57 86 | 
             
            - lib/rails/annotate/solargraph.rb
         | 
| 58 87 | 
             
            - lib/rails/annotate/solargraph/configuration.rb
         | 
| @@ -67,6 +96,7 @@ licenses: | |
| 67 96 | 
             
            metadata:
         | 
| 68 97 | 
             
              homepage_uri: https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph
         | 
| 69 98 | 
             
              source_code_uri: https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph
         | 
| 99 | 
            +
              changelog_uri: https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph/-/raw/main/CHANGELOG.md
         | 
| 70 100 | 
             
            post_install_message:
         | 
| 71 101 | 
             
            rdoc_options: []
         | 
| 72 102 | 
             
            require_paths:
         |