├── .rspec
├── spec
├── fixtures
│ └── source.rb
├── lecter_spec.rb
├── spec_helper.rb
├── formatter_headers_spec.rb
├── formatter_payload_spec.rb
├── html_generator_spec.rb
├── html_row_spec.rb
└── requester_spec.rb
├── Gemfile
├── lib
├── lecter
│ ├── version.rb
│ ├── engine.rb
│ ├── railtie.rb
│ ├── formatter_headers.rb
│ ├── formatter_payload.rb
│ ├── rack.rb
│ ├── trace_point.rb
│ ├── html_row.rb
│ ├── requester.rb
│ └── html_generator.rb
└── lecter.rb
├── bin
├── setup
├── console
└── rails
├── Rakefile
├── config
├── routes.rb
└── locales
│ ├── en.yml
│ └── ru.yml
├── .gitignore
├── CHANGELOG.md
├── .rubocop.yml
├── .all-contributorsrc
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── PULL_REQUEST_TEMPLATE.md
├── LICENSE.txt
├── app
├── controllers
│ └── lecter
│ │ └── diagnosis_controller.rb
└── views
│ ├── lecter
│ └── diagnosis
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ └── layouts
│ └── lecter.html.erb
├── CONTRIBUTING.md
├── lecter.gemspec
├── Gemfile.lock
├── .circleci
└── config.yml
├── CODE_OF_CONDUCT.md
└── README.md
/.rspec:
--------------------------------------------------------------------------------
1 | --format documentation
2 | --color
3 | --require spec_helper
4 |
--------------------------------------------------------------------------------
/spec/fixtures/source.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | some ruby code
4 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source 'https://rubygems.org'
4 |
5 | gemspec
6 |
--------------------------------------------------------------------------------
/lib/lecter/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | VERSION = '0.2.0'
5 | end
6 |
--------------------------------------------------------------------------------
/lib/lecter/engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class Engine < ::Rails::Engine
5 | isolate_namespace Lecter
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 | IFS=$'\n\t'
4 | set -vx
5 |
6 | bundle install
7 |
8 | # Do any other automated setup that you need to do here
9 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'bundler/gem_tasks'
4 | require 'rspec/core/rake_task'
5 |
6 | RSpec::Core::RakeTask.new(:spec)
7 |
8 | task default: :spec
9 |
--------------------------------------------------------------------------------
/spec/lecter_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | RSpec.describe Lecter do
4 | it 'has a version number' do
5 | expect(Lecter::VERSION).not_to be nil
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Lecter::Engine.routes.draw do
4 | root 'diagnosis#new'
5 |
6 | resource :diagnosis, only: %w[new create show], controller: :diagnosis
7 | end
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.bundle/
2 | /.yardoc
3 | /_yardoc/
4 | /coverage/
5 | /doc/
6 | /pkg/
7 | /spec/reports/
8 | /tmp/
9 |
10 | # rspec failure tracking
11 | .rspec_status
12 | .idea/
13 | *.gem
14 | coverage
15 |
--------------------------------------------------------------------------------
/lib/lecter/railtie.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class LecterRailtie < Rails::Railtie
5 | initializer 'lecter.configure_rails_initialization' do |app|
6 | app.middleware.use Lecter::Rack
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require 'bundler/setup'
5 | require 'lecter'
6 |
7 | # You can add fixtures and/or initialization code here to make experimenting
8 | # with your gem easier. You can also use a different console, if you like.
9 |
10 | # (If you use this, don't forget to add pry to your Gemfile!)
11 | # require "pry"
12 | # Pry.start
13 |
14 | require 'irb'
15 | IRB.start(__FILE__)
16 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | layouts:
3 | lecter:
4 | new_diagnosis: 'New diagnosis'
5 | lecter:
6 | diagnosis:
7 | show:
8 | title: 'Diagnosis results'
9 | executed_code: 'Executed code:'
10 | new:
11 | title: 'New diagnosis'
12 | endpoint: 'Endpoint'
13 | body_raw: 'Body (raw)'
14 | method: 'HTTP method'
15 | send: 'Send request'
16 | headers: 'Headers'
17 |
--------------------------------------------------------------------------------
/config/locales/ru.yml:
--------------------------------------------------------------------------------
1 | ru:
2 | layouts:
3 | lecter:
4 | new_diagnosis: 'Новый диагноз'
5 | lecter:
6 | diagnosis:
7 | show:
8 | title: 'Диагноз'
9 | executed_code: 'Используемый код:'
10 | new:
11 | title: 'Новый диагноз'
12 | endpoint: 'Абсолютный путь'
13 | body_raw: 'Тело запроса'
14 | method: 'HTTP метод'
15 | send: 'Послать запрос'
16 | headers: 'Заголовки'
17 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'bundler/setup'
4 | require 'lecter'
5 | require 'simplecov'
6 |
7 | SimpleCov.start
8 |
9 | RSpec.configure do |config|
10 | # Enable flags like --only-failures and --next-failure
11 | config.example_status_persistence_file_path = '.rspec_status'
12 |
13 | # Disable RSpec exposing methods globally on `Module` and `main`
14 | config.disable_monkey_patching!
15 |
16 | config.expect_with :rspec do |c|
17 | c.syntax = :expect
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/lecter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'lecter/engine' if defined?(Rails::Engine)
4 | require 'lecter/formatter_payload'
5 | require 'lecter/html_generator'
6 | require 'lecter/html_row'
7 | require 'lecter/rack'
8 | require 'lecter/railtie' if defined?(Rails::Railtie)
9 | require 'lecter/requester'
10 | require 'lecter/version'
11 | require 'lecter/trace_point'
12 | require 'lecter/formatter_headers'
13 |
14 | require 'rest-client'
15 |
16 | module Lecter
17 | AVAILABLE_METHODS = %w[GET POST PUT PATCH DELETE].freeze
18 | DEFAULT_METHOD = 'GET'
19 | end
20 |
--------------------------------------------------------------------------------
/spec/formatter_headers_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'spec_helper'
4 |
5 | RSpec.describe Lecter::FormatterHeaders, type: :service do
6 | let(:headers) { 'content_type=text/html,accept=*/*' }
7 |
8 | subject { described_class.new(headers).call }
9 |
10 | it 'returns a hash' do
11 | is_expected.to eq({ 'content_type' => 'text/html', 'accept' => '*/*' })
12 | end
13 |
14 | context 'if headers is empty string' do
15 | let(:headers) { '' }
16 |
17 | it 'returns an empty hash' do
18 | is_expected.to eq({})
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change log
2 |
3 | ## master (unreleased)
4 |
5 | ### New features
6 | ### Bug fixes
7 | ### Changes
8 |
9 | ## 0.2.0 (2022-02-15)
10 |
11 | ### New features
12 |
13 | * [issue#74](https://github.com/Neodelf/lecter/pull/79): Add the headers parameters in the form ([@neodelf][])
14 |
15 | ### Changes
16 |
17 | * [PR](https://github.com/Neodelf/lecter/pull/69): Set the simplecov gem version to 0.17.1 ([@neodelf][])
18 | * [commit](https://github.com/Neodelf/lecter/commit/73e0ed69cf8e1773abed9e9b735e0742aa63dade): Update makeup. ([@neodelf][])
19 |
20 | [@neodelf]: https://github.com/neodelf
21 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | # This command will automatically be run when you run "rails" with Rails gems
5 | # installed from the root of your application.
6 |
7 | ENGINE_ROOT = File.expand_path('..', __dir__)
8 | ENGINE_PATH = File.expand_path('../lib/lecter/engine', __dir__)
9 | APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
10 |
11 | # Set up gems listed in the Gemfile.
12 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
13 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
14 |
15 | require 'rails/all'
16 | require 'rails/engine/commands'
17 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | AllCops:
2 | Exclude:
3 | - 'lib/lecter/html_generator.rb'
4 | - 'lib/lecter/rack.rb'
5 | - 'lib/lecter/trace_point.rb'
6 | - 'vendor/**/*'
7 | Documentation:
8 | Enabled: false
9 | Layout/LineLength:
10 | Max: 100
11 | Lint/RaiseException:
12 | Enabled: true
13 | Lint/StructNewOverride:
14 | Enabled: true
15 | Style/HashEachMethods:
16 | Enabled: true
17 | Style/HashTransformKeys:
18 | Enabled: true
19 | Style/HashTransformValues:
20 | Enabled: true
21 | Metrics/BlockLength:
22 | ExcludedMethods: ['describe', 'context']
23 | Layout/ArrayAlignment:
24 | EnforcedStyle: with_fixed_indentation
25 | IndentationWidth: 2
26 |
--------------------------------------------------------------------------------
/lib/lecter/formatter_headers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class FormatterHeaders
5 | WRONG_HEADERS_MSG = 'Wrong headers'
6 | attr_reader :result, :error_message
7 |
8 | def initialize(headers)
9 | @dirty_headers = headers
10 | end
11 |
12 | def call
13 | @result = dirty_headers
14 | .split(',')
15 | .map { |header_with_value| header_with_value.split('=') }
16 | .to_h
17 | rescue StandardError
18 | @error_message = WRONG_HEADERS_MSG
19 | false
20 | end
21 |
22 | private
23 |
24 | attr_accessor :dirty_headers
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | "README.md"
4 | ],
5 | "imageSize": 100,
6 | "commit": false,
7 | "contributors": [
8 | {
9 | "login": "pineapplethief",
10 | "name": "Aleksey Glukhov",
11 | "avatar_url": "https://avatars1.githubusercontent.com/u/4012690?v=4",
12 | "profile": "https://github.com/pineapplethief",
13 | "contributions": [
14 | "code",
15 | "doc",
16 | "maintenance"
17 | ]
18 | }
19 | ],
20 | "contributorsPerLine": 7,
21 | "projectName": "lecter",
22 | "projectOwner": "Neodelf",
23 | "repoType": "github",
24 | "repoHost": "https://github.com",
25 | "skipCi": true
26 | }
27 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Report an issue with Lecter you've found.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **Actual behavior**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See an error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem, please.
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
--------------------------------------------------------------------------------
/spec/formatter_payload_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'spec_helper'
4 |
5 | RSpec.describe Lecter::FormatterPayload, type: :service do
6 | let(:payload) { '"post"=>{"title"=>"New title", "description"=>"Desciption"}' }
7 |
8 | subject { described_class.new(payload).call }
9 |
10 | it 'returns hash' do
11 | is_expected.to eq(
12 | {
13 | lecter_enabled: true,
14 | 'post' => { 'description' => 'Desciption', 'title' => 'New title' }
15 | }
16 | )
17 | end
18 |
19 | context 'if payload is empty string' do
20 | let(:payload) { '' }
21 |
22 | it 'returns hash' do
23 | is_expected.to eq({ lecter_enabled: true })
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest new Lecter features or improvements to existing features.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Replace this text with a summary of the changes in your PR.
2 | The more detailed you are, the better.**
3 |
4 | -----------------
5 |
6 | Before submitting the PR make sure the following are checked:
7 |
8 | * [ ] The PR relates to *only* one subject with a clear title and description in grammatically correct, complete sentences.
9 | * [ ] Wrote [good commit messages][1].
10 | * [ ] Commit message starts with `[Fix #issue-number]` (if the related issue exists).
11 | * [ ] Feature branch is up-to-date with `master` (if not - rebase it).
12 | * [ ] Squashed related commits together.
13 | * [ ] Added tests.
14 | * [ ] Ran `bundle exec rake default`. It executes all tests and runs RuboCop on its own code.
15 |
16 | [1]: https://chris.beams.io/posts/git-commit/
17 |
--------------------------------------------------------------------------------
/lib/lecter/formatter_payload.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'json'
4 |
5 | module Lecter
6 | class FormatterPayload
7 | WRONG_PARAMETERS_MSG = 'Wrong parameters'
8 | attr_reader :result, :error_message
9 |
10 | def initialize(payload)
11 | @dirty_payload = payload
12 | end
13 |
14 | def call
15 | @result = json_parse(dirty_payload).merge(lecter_enabled_parameter)
16 | rescue JSON::ParserError
17 | @error_message = WRONG_PARAMETERS_MSG
18 | false
19 | end
20 |
21 | private
22 |
23 | attr_accessor :dirty_payload
24 |
25 | def json_parse(string)
26 | string = '{' + string + '}' unless string.match(/\A{.*}\z/)
27 | string.gsub!('=>', ':')&.gsub!(/(“|”)/, '"')
28 | JSON.parse(string)
29 | end
30 |
31 | def lecter_enabled_parameter
32 | { lecter_enabled: true }
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/lecter/rack.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class Rack
5 | def initialize(app)
6 | @app = app
7 | @tp = Lecter::TracePoint.new.build
8 | end
9 |
10 | def call(env)
11 | if ::Rack::Request.new(env).params['lecter_enabled']
12 | thread = Thread.current
13 | thread[:items] = ''
14 | tp.enable
15 | ActionController::Base.allow_forgery_protection = false
16 | end
17 |
18 | status, headers, response = @app.call(env)
19 |
20 | if tp.enabled?
21 | response = [status.to_s + thread[:items]]
22 | status = 200
23 | headers = {}
24 | end
25 |
26 | [status, headers, response]
27 | ensure
28 | if tp.enabled?
29 | tp.disable
30 | ActionController::Base.allow_forgery_protection = true
31 | Thread.current[:items] = nil
32 | end
33 | end
34 |
35 | private
36 |
37 | attr_reader :tp
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/lecter/trace_point.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class TracePoint
5 | def build
6 | tp = ::TracePoint.new(:line, :class, :call, :c_call, :return) do |trace_point|
7 | if trace_point.path&.exclude?('/app/views') &&
8 | trace_point.path&.exclude?('/app/helpers') &&
9 | trace_point.path&.include?(Rails.root.to_s) &&
10 | trace_point.method_id != :method_added &&
11 | trace_point.defined_class != Module &&
12 | trace_point.defined_class != Class &&
13 | trace_point.defined_class != String &&
14 | trace_point.defined_class != Kernel &&
15 | trace_point.defined_class != NilClass
16 |
17 | Thread.current[:items] += [
18 | trace_point.path,
19 | trace_point.lineno,
20 | trace_point.defined_class,
21 | trace_point.method_id,
22 | trace_point.event
23 | ].join(' ') + ';'
24 | end
25 | end
26 |
27 | tp
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/spec/html_generator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'spec_helper'
4 |
5 | RSpec.describe Lecter::HtmlGenerator, type: :service do
6 | let(:data) do
7 | [{ 'spec/fixtures/source.rb' => [3] }]
8 | end
9 |
10 | subject { described_class.new(data).call }
11 |
12 | it 'returns array of Lecter::FileListing objects' do
13 | all_elements_has_specific_class = subject.inject(true) do |memo, object|
14 | memo && object.is_a?(Lecter::FileListing)
15 | end
16 |
17 | expect(all_elements_has_specific_class).to be_truthy
18 | end
19 |
20 | it 'returns file_path object params' do
21 | expect(subject.first.file_path)
22 | .to eq('spec/fixtures/source.rb')
23 | end
24 |
25 | it 'returns value object params' do
26 | expect(subject.first.html_rows).to eq(
27 | [
28 | "
1 # frozen_string_literal: true \n
",
29 | "2 \n
",
30 | "3 some ruby code -> 1\n
"
31 | ]
32 | )
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Neodelf
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/lecter/html_row.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class HtmlRow
5 | ARROW = '-> '
6 | BACKGROUND_INCLUDED_ROW = '#4a4a4a'
7 | NEW_LINE_SYMBOL = "\n"
8 |
9 | def initialize(row, row_number, row_executable, order_of_executed_lines)
10 | @row = row
11 | @row_number = row_number
12 | @row_executable = row_executable
13 | @order_of_executed_lines = order_of_executed_lines
14 | end
15 |
16 | def create
17 | "#{html_row}
"
18 | end
19 |
20 | private
21 |
22 | attr_reader :row, :row_number, :row_executable, :order_of_executed_lines
23 |
24 | def html_row
25 | [row_number, row, row_calling_order_number].join(' ') + NEW_LINE_SYMBOL
26 | end
27 |
28 | def row_calling_order_number
29 | return unless row_executable
30 |
31 | ARROW + order_of_executed_lines
32 | .each_with_index
33 | .select { |_, index| order_of_executed_lines[index] == row_number }
34 | .map { |_, index| index + 1 }
35 | .join(', ')
36 | end
37 |
38 | def style
39 | row_executable ? "background-color: #{BACKGROUND_INCLUDED_ROW};" : nil
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/app/controllers/lecter/diagnosis_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class DiagnosisController < ActionController::Base
5 | layout 'lecter'
6 | before_action :format_request_data, only: :create
7 |
8 | def new; end
9 |
10 | def show
11 | redirect_to new_diagnosis_path
12 | end
13 |
14 | def create
15 | requester = Lecter::Requester.new(requester_params)
16 | if requester.call
17 | @file_listings = HtmlGenerator.new(requester.lines).call
18 | render :show
19 | else
20 | flash[:error] = requester.error_message
21 | render :new
22 | end
23 | end
24 |
25 | private
26 |
27 | def diagnosis_params
28 | params.permit(:endpoint, :body_raw, :method, :headers)
29 | end
30 |
31 | def requester_params
32 | {
33 | method: diagnosis_params[:method].downcase.to_sym,
34 | url: diagnosis_params[:endpoint],
35 | payload: formatter_payload.result,
36 | headers: formatted_headers.result
37 | }
38 | end
39 |
40 | def format_request_data
41 | formatters = [formatter_payload, formatted_headers]
42 | return if formatters.all?(&:call)
43 |
44 | flash[:error] = formatters.map(&:error_message).join(', ')
45 | render :new
46 | end
47 |
48 | def formatter_payload
49 | @formatter_payload ||= Lecter::FormatterPayload.new(diagnosis_params[:body_raw])
50 | end
51 |
52 | def formatted_headers
53 | @formatted_headers ||= Lecter::FormatterHeaders.new(diagnosis_params[:headers])
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/lib/lecter/requester.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class Requester
5 | WRONG_URL_MSG = 'Wrong url'
6 |
7 | attr_reader :lines, :error_message
8 |
9 | def initialize(params)
10 | @method = params[:method]
11 | @url = params[:url]
12 | @payload = params[:payload]
13 | @lines = []
14 | @headers = params[:headers]
15 | end
16 |
17 | def call
18 | return false unless response
19 |
20 | prepare_lines
21 | rescue URI::InvalidURIError
22 | @error_message = WRONG_URL_MSG
23 | false
24 | rescue RestClient::ExceptionWithResponse => e
25 | @error_message = e.message
26 | false
27 | end
28 |
29 | private
30 |
31 | attr_accessor :method, :url, :payload, :headers
32 |
33 | def prepare_lines
34 | items.each do |item|
35 | file, line_number = item.split(' ')
36 | line_number = line_number.to_i
37 |
38 | if line_belongs_to_last?(file)
39 | lines.last[file] = lines.last[file] << line_number
40 | else
41 | lines << { file.to_s => [line_number] }
42 | end
43 | end
44 | end
45 |
46 | def response
47 | @response ||= RestClient::Request.execute(
48 | method: method,
49 | url: url,
50 | payload: payload,
51 | headers: headers
52 | )
53 | end
54 |
55 | def items
56 | @items ||= response.body[3..-1].split(';')
57 | end
58 |
59 | def line_belongs_to_last?(file)
60 | lines.last.is_a?(Hash) && lines.last.keys.first.to_s == file
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | If you discover issues, have ideas for improvements or new features,
4 | please report them to the [issue tracker][1] of the repository or
5 | submit a pull request. Please, try to follow these guidelines when you
6 | do so.
7 |
8 | ## Issue reporting
9 |
10 | * Check that the issue has not already been reported.
11 | * Check that the issue has not already been fixed in the latest code
12 | (a.k.a. `master`).
13 | * Be clear, concise and precise in your description of the problem.
14 | * Open an issue with a descriptive title and a summary in grammatically correct,
15 | complete sentences.
16 |
17 | * Include any relevant code to the issue summary.
18 |
19 | ## Pull requests
20 |
21 | * Read [how to properly contribute to open source projects on GitHub][1].
22 | * Fork the project.
23 | * Use a topic/feature branch to easily amend a pull request later, if necessary.
24 | * Write [good commit messages][2].
25 | * Use the same coding conventions as the rest of the project.
26 | * Commit and push until you are happy with your contribution.
27 | * If your change has a corresponding open GitHub issue, prefix the commit message with `[Fix #github-issue-number]`.
28 | * Make sure to add tests for it. This is important so I don't break it
29 | in a future version unintentionally.
30 | * Open a [pull request][3] that relates to *only* one subject with a clear title
31 | and description in grammatically correct, complete sentences.
32 |
33 | [1]: https://www.gun.io/blog/how-to-github-fork-branch-and-pull-request
34 | [2]: https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
35 | [3]: https://help.github.com/articles/about-pull-requests
36 |
--------------------------------------------------------------------------------
/lecter.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | lib = File.expand_path('lib', __dir__)
4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5 | require 'lecter/version'
6 |
7 | Gem::Specification.new do |spec|
8 | spec.name = 'lecter'
9 | spec.version = Lecter::VERSION
10 | spec.authors = ['Neodelf']
11 | spec.email = ['neodelf@gmail.com']
12 |
13 | spec.summary = 'Show executable code by request.'
14 | spec.description = 'The main purpose of that gem is helping developers to understand which '\
15 | 'code executes by request.
'
16 | spec.homepage = 'https://github.com/neodelf/lecter'
17 | spec.license = 'MIT'
18 |
19 | spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20 |
21 | spec.metadata['homepage_uri'] = spec.homepage
22 | # spec.metadata["source_code_uri"] = "Put your gem's public repo URL here."
23 | # spec.metadata["changelog_uri"] = "Put your gem's CHANGELOG.md URL here."
24 |
25 | # Specify which files should be added to the gem when it is released.
26 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27 | spec.files = Dir.chdir(File.expand_path(__dir__)) do
28 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
29 | end
30 | spec.bindir = 'exe'
31 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32 | spec.require_paths = ['lib']
33 |
34 | spec.add_development_dependency 'bundler', '~> 2.0'
35 | spec.add_development_dependency 'rake', '~> 13.0'
36 | spec.add_development_dependency 'rspec', '~> 3.0'
37 | spec.add_development_dependency 'rubocop'
38 |
39 | spec.add_runtime_dependency 'rest-client'
40 | spec.add_runtime_dependency 'simplecov', '0.17.1'
41 | end
42 |
--------------------------------------------------------------------------------
/spec/html_row_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'spec_helper'
4 |
5 | RSpec.describe Lecter::HtmlRow, type: :service do
6 | let(:row) { 'some code in ruby' }
7 | let(:row_number) { 1 }
8 | let(:row_executable) { true }
9 | let(:order_of_executed_lines) { [1] }
10 |
11 | subject { described_class.new(row, row_number, row_executable, order_of_executed_lines).create }
12 |
13 | context 'if row is executable' do
14 | it 'adds executable order to the end of row' do
15 | is_expected.to end_with(
16 | "1 some \
17 | code in ruby -> 1\n
"
18 | )
19 | end
20 |
21 | context 'if row is executed two times' do
22 | let(:order_of_executed_lines) { [1, 1] }
23 |
24 | it 'adds executable order to the end of row' do
25 | is_expected.to end_with("-> 1, 2\n")
26 | end
27 | end
28 |
29 | context 'if executing row is not consistently' do
30 | let(:order_of_executed_lines) { [1, 2, 1] }
31 |
32 | it 'adds executable order to the end of row' do
33 | is_expected.to end_with("-> 1, 3\n")
34 | end
35 | end
36 |
37 | context 'if executing row is last in order' do
38 | let(:order_of_executed_lines) { [2, 1] }
39 |
40 | it 'adds executable order to the end of row' do
41 | is_expected.to end_with("-> 2\n")
42 | end
43 | end
44 | end
45 |
46 | context 'if row is not executable' do
47 | let(:row_executable) { false }
48 |
49 | it 'adds background color' do
50 | is_expected.not_to include("background-color: #{described_class::BACKGROUND_INCLUDED_ROW}")
51 | end
52 |
53 | it 'adds arrow' do
54 | is_expected.not_to include(described_class::ARROW)
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/lib/lecter/html_generator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Lecter
4 | class HtmlGenerator
5 | COUNT_LINES_AROUND_RUNNING_ROW = 5
6 | ELLIPSIS = '...'
7 | NEW_LINE = "\n"
8 |
9 | def initialize(data)
10 | @data = data
11 | end
12 |
13 | def call
14 | @data.each.map do |item|
15 | @file_path = item.keys.first
16 | @executable_row_numbers = item.values.flatten
17 | previous_row_is_empty = false
18 |
19 | html_rows = file_context.each_with_index.map do |file_row, file_row_index|
20 | @file_row_index = file_row_index
21 | row_executable = executable_row_numbers.include?(file_row_index + 1)
22 |
23 | if row_executable || file_row_in_showing_range?(file_row_index)
24 | previous_row_is_empty = false
25 | Lecter::HtmlRow.new(
26 | file_row,
27 | file_row_index + 1,
28 | row_executable,
29 | executable_row_numbers
30 | ).create
31 | elsif !previous_row_is_empty
32 | previous_row_is_empty = true
33 | ELLIPSIS + NEW_LINE
34 | end
35 | end
36 |
37 | FileListing.new(file_path, html_rows)
38 | end
39 | end
40 |
41 | private
42 |
43 | attr_accessor :executable_row_numbers, :file_row_index, :file_path
44 |
45 | def file_row_in_showing_range?(_index)
46 | executable_row_numbers.reduce(false) do |memo, row_number|
47 | memo ||
48 | (row_number - COUNT_LINES_AROUND_RUNNING_ROW - 1..
49 | row_number + COUNT_LINES_AROUND_RUNNING_ROW - 1).include?(file_row_index)
50 | end
51 | end
52 |
53 | def file_context
54 | File.open(file_path, 'r').read.split(NEW_LINE)
55 | end
56 | end
57 |
58 | class FileListing
59 | attr_reader :file_path, :html_rows
60 |
61 | def initialize(file_path, html_rows)
62 | @file_path = file_path
63 | @html_rows = html_rows
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | lecter (0.2.0)
5 | rest-client
6 | simplecov (= 0.17.1)
7 |
8 | GEM
9 | remote: https://rubygems.org/
10 | specs:
11 | ast (2.4.0)
12 | diff-lcs (1.3)
13 | docile (1.4.0)
14 | domain_name (0.5.20190701)
15 | unf (>= 0.0.5, < 1.0.0)
16 | http-accept (1.7.0)
17 | http-cookie (1.0.4)
18 | domain_name (~> 0.5)
19 | jaro_winkler (1.5.4)
20 | json (2.3.0)
21 | mime-types (3.4.1)
22 | mime-types-data (~> 3.2015)
23 | mime-types-data (3.2022.0105)
24 | netrc (0.11.0)
25 | parallel (1.19.1)
26 | parser (2.7.1.0)
27 | ast (~> 2.4.0)
28 | rainbow (3.0.0)
29 | rake (13.0.1)
30 | rest-client (2.1.0)
31 | http-accept (>= 1.7.0, < 2.0)
32 | http-cookie (>= 1.0.2, < 2.0)
33 | mime-types (>= 1.16, < 4.0)
34 | netrc (~> 0.8)
35 | rexml (3.2.5)
36 | rspec (3.8.0)
37 | rspec-core (~> 3.8.0)
38 | rspec-expectations (~> 3.8.0)
39 | rspec-mocks (~> 3.8.0)
40 | rspec-core (3.8.2)
41 | rspec-support (~> 3.8.0)
42 | rspec-expectations (3.8.4)
43 | diff-lcs (>= 1.2.0, < 2.0)
44 | rspec-support (~> 3.8.0)
45 | rspec-mocks (3.8.1)
46 | diff-lcs (>= 1.2.0, < 2.0)
47 | rspec-support (~> 3.8.0)
48 | rspec-support (3.8.2)
49 | rubocop (0.81.0)
50 | jaro_winkler (~> 1.5.1)
51 | parallel (~> 1.10)
52 | parser (>= 2.7.0.1)
53 | rainbow (>= 2.2.2, < 4.0)
54 | rexml
55 | ruby-progressbar (~> 1.7)
56 | unicode-display_width (>= 1.4.0, < 2.0)
57 | ruby-progressbar (1.10.1)
58 | simplecov (0.17.1)
59 | docile (~> 1.1)
60 | json (>= 1.8, < 3)
61 | simplecov-html (~> 0.10.0)
62 | simplecov-html (0.10.2)
63 | unf (0.1.4)
64 | unf_ext
65 | unf_ext (0.0.8)
66 | unicode-display_width (1.7.0)
67 |
68 | PLATFORMS
69 | ruby
70 |
71 | DEPENDENCIES
72 | bundler (~> 2.0)
73 | lecter!
74 | rake (~> 13.0)
75 | rspec (~> 3.0)
76 | rubocop
77 |
78 | BUNDLED WITH
79 | 2.1.2
80 |
--------------------------------------------------------------------------------
/app/views/lecter/diagnosis/new.html.erb:
--------------------------------------------------------------------------------
1 | <%= content_for :title, t('.title') %>
2 |
3 |
4 |
<%= t('.title') %>
5 |
6 | <%= form_tag diagnosis_path do %>
7 | <% flash.each do |key, value| %>
8 |
9 | <%= value %>
10 |
11 | <% end %>
12 |
13 | <%= label_tag t('.method'), nil, class: 'col-sm-2 col-form-label' %>
14 |
15 | <%= select_tag :method, options_for_select(Lecter::AVAILABLE_METHODS, Lecter::DEFAULT_METHOD) %>
16 |
17 |
18 | Choose one
19 |
20 |
21 |
22 | <%= label_tag t('.endpoint'), nil, class: 'col-sm-2 col-form-label' %>
23 |
24 | <%= text_field_tag :endpoint, nil, class: 'form-control', placeholder: 'Endpoint' %>
25 |
26 |
27 | localhost:3000/posts
28 |
29 |
30 |
31 | <%= label_tag t('.headers'), nil, class: 'col-sm-2 col-form-label' %>
32 |
33 | <%= text_field_tag :headers, nil, class: 'form-control', placeholder: 'Headers' %>
34 |
35 |
36 | content_type=text/html,accept=*/*
37 |
38 |
39 |
40 | <%= label_tag t('.body_raw'), nil, class: 'col-sm-2 col-form-label' %>
41 |
42 | <%= text_area_tag :body_raw, nil, rows: 10, class: 'form-control', placeholder: 'Body(raw)' %>
43 |
44 |
45 | "post" => {
46 | "title" => "New title",
47 | "description" => "Desciption"
48 | }
49 |
50 |
51 |
52 |
53 | <%= submit_tag t('.send'), class: 'btn btn-primary' %>
54 | <% end %>
55 |
56 |
57 |
--------------------------------------------------------------------------------
/spec/requester_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'spec_helper'
4 |
5 | RSpec.describe Lecter::Requester do
6 | let(:specific_parameter) { { lecter_enabled: true } }
7 | let(:url) { 'localhost:3009/posts' }
8 | let(:payload) { { 'post' => { 'title' => 'New title', 'description' => 'New description' } } }
9 | let(:headers) { { content_type: 'text/html', accept: '*/*' } }
10 | let(:params) do
11 | { method: :anything, url: url, payload: payload, lecter_enabled: true, headers: headers }
12 | end
13 | let(:instance) { described_class.new(params) }
14 |
15 | subject { instance.call }
16 |
17 | context 'if all params are valid' do
18 | before do
19 | response = instance_double(
20 | RestClient::Response,
21 | body: "\
22 | 302/absolute_path_to_app/app/controllers/posts_controller.rb 26 PostsController create call;\
23 | /absolute_path_to_app/app/controllers/posts_controller.rb 27 PostsController create line;\
24 | /absolute_path_to_app/app/controllers/posts_controller.rb 71 PostsController post_params call;\
25 | /absolute_path_to_app/app/controllers/posts_controller.rb 72 PostsController post_params line;/\
26 | absolute_path_to_app/app/controllers/posts_controller.rb 73 PostsController post_params return;/\
27 | absolute_path_to_app/app/controllers/posts_controller.rb 29 PostsController create line;\
28 | /absolute_path_to_app/app/controllers/posts_controller.rb 30 PostsController create line;\
29 | /absolute_path_to_app/app/controllers/posts_controller.rb 31 PostsController create line;\
30 | /absolute_path_to_app/app/controllers/posts_controller.rb 32 PostsController create line;\
31 | /absolute_path_to_app/app/controllers/posts_controller.rb 31 PostsController create line;\
32 | /absolute_path_to_app/app/controllers/posts_controller.rb 38 PostsController create return;"
33 | )
34 | allow(RestClient::Request).to receive(:execute).and_return(response)
35 | subject
36 | end
37 |
38 | it 'generate lines as hash in right format' do
39 | expect(instance.lines).to eq(
40 | [
41 | {
42 | '/absolute_path_to_app/app/controllers/posts_controller.rb' =>
43 | [26, 27, 71, 72, 73, 29, 30, 31, 32, 31, 38]
44 | }
45 | ]
46 | )
47 | end
48 | end
49 |
50 | [RestClient::ExceptionWithResponse, URI::InvalidURIError].each do |error|
51 | context "if raise #{error}" do
52 | before do
53 | allow(RestClient::Request).to receive(:execute).and_raise(error)
54 | end
55 |
56 | it 'returns false' do
57 | is_expected.to be_falsey
58 | end
59 |
60 | it 'make :lines nil' do
61 | expect(instance.lines).to be_empty
62 | end
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | working_directory: ~/bikeindex/bike_index
5 | environment:
6 | COVERAGE: true
7 | docker:
8 | - image: circleci/ruby:2.6.3
9 | steps:
10 | - checkout
11 | - restore_cache:
12 | keys:
13 | # This branch if available
14 | - v2-dep-{{ .Branch }}-
15 | # Default branch if not
16 | - v2-dep-master-
17 | # Any branch if there are none on the default branch - this should be unnecessary if you have your default branch configured correctly
18 | - v2-dep-
19 | - run:
20 | name: Install Bundler
21 | command: gem install bundler -v 2.1.2
22 | - run:
23 | name: Bundle Gems
24 | command: bundle install --path=vendor/bundle --jobs=4 --retry=3
25 | - run:
26 | name: Rubocop
27 | command: bundle exec rubocop
28 | - run:
29 | name: Install Code Climate Test Reporter
30 | command: |
31 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
32 | chmod +x ./cc-test-reporter
33 | - save_cache:
34 | key: v2-dep-{{ .Branch }}-{{ epoch }}
35 | paths:
36 | - ./vendor/bundle
37 | - ~/.bundle
38 | - run:
39 | name: Run tests
40 | command: |
41 | ./cc-test-reporter before-build
42 | TESTFILES=$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
43 | bundle exec rspec --profile 10 \
44 | --color \
45 | --order random \
46 | --format progress \
47 | -- ${TESTFILES}
48 | - run:
49 | name: Code Climate Test Coverage
50 | command: |
51 | ./cc-test-reporter format-coverage -t simplecov -o "coverage/codeclimate.$CIRCLE_NODE_INDEX.json"
52 | - persist_to_workspace:
53 | root: coverage
54 | paths:
55 | - codeclimate.*.json
56 |
57 | upload-coverage:
58 | docker:
59 | - image: circleci/ruby:2.6.3
60 | environment:
61 | CC_TEST_REPORTER_ID: 9ef6750a0b374973f31c70ccf4bc6be1a4c93b0f2d3537d16e77450ef01f7813
62 | working_directory: ~/bikeindex/bike_index
63 |
64 | steps:
65 | - attach_workspace:
66 | at: ~/bikeindex/bike_index
67 | - run:
68 | name: Install Code Climate Test Reporter
69 | command: |
70 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
71 | chmod +x ./cc-test-reporter
72 | - run:
73 | name: Upload Test Reporter To Codeclimate
74 | command: |
75 | ./cc-test-reporter sum-coverage codeclimate.*.json --output codeclimate.total.json
76 | ./cc-test-reporter upload-coverage --input codeclimate.total.json
77 |
78 | workflows:
79 | version: 2
80 |
81 | commit:
82 | jobs:
83 | - build
84 | - upload-coverage:
85 | requires:
86 | - build
87 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at neodelf@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/app/views/layouts/lecter.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= yield(:title) %>
4 | <%= javascript_include_tag '//code.jquery.com/jquery-1.12.4.js', '//code.jquery.com/ui/1.12.1/jquery-ui.js' %>
5 | <%= javascript_include_tag 'https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js' %>
6 | <%= stylesheet_link_tag 'https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css' %>
7 |
8 |
9 |
252 |
253 |
254 |
255 | <%= yield %>
256 |
257 |
258 |
259 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
Lecter shows an executed code by a URL request.
5 | Debug an unknown code in SECONDS!
6 |
7 |
8 | [![Gem Version][0]][1]
9 | [![Ruby Style Guide][15]][16]
10 | [![CircleCI][2]][3]
11 | [![Test Coverage][12]][13]
12 | [![Maintainability][10]][11]
13 | [](#contributors-)
14 |
15 |
16 | > Quid pro quo. I tell you things, you tell me things. Not about this case, though. About yourself.
17 | > -- Hannibal Lecter / The Silence of the Lambs
18 |
19 | ----------
20 |
21 | ## Table of contents
22 | * [:rotating_light: Problems](#rotating_light-problems)
23 | * [:rocket: Solutions](#rocket-solutions)
24 | * [:bangbang: Requirements](#bangbang-requirements)
25 | * [:hammer_and_wrench: Installation](#hammer_and_wrench-installation)
26 | * [:joystick: Usage](#joystick-usage)
27 | * [:man_technologist: Examples](#man_technologist-examples)
28 | * [:heart: Sponsors](#card_file_box-license)
29 | * [:desktop_computer: Contributing & Contributors](#desktop_computer-contributing--contributors)
30 | * [:card_file_box: License](#card_file_box-license)
31 |
32 | ## :rotating_light: Problems
33 | 1. Developers **don't know** how their app works.
34 | 2. Reading code is a **long** process.
35 | 3. Memorizing many lines of code is **difficult**.
36 |
37 | ## :rocket: Solutions
38 | 1. The main purpose of this gem is **to help developers understand which code is executed** by a request.
39 |
40 | 2. Gem's purpose could be compared to visiting a doctor:
41 | You give the symptoms of your disease and **receive a diagnosis**.
42 | You give the parameters of a request and **receive executable code**.
43 |
44 | 3. You don't have to work with debuggers, read and remember many lines of code.
45 | Just **give & receive**!
46 |
47 | ## :bangbang: Requirements
48 | Please **use a multithreading server** such as a [puma][4] server with more than `1` worker.
49 | For more information about how to tune a puma server, please visit this [link][5].
50 |
51 | ## :hammer_and_wrench: Installation
52 | Installing is a **very simple** process.
53 |
54 | 1. **Add** the gem to your Gemfile:
55 |
56 | ```ruby
57 | gem 'lecter'
58 | ```
59 |
60 | 2. **Execute** in a terminal in your app's directory:
61 |
62 | ```zsh
63 | bundle install
64 | ```
65 |
66 | 3. **Add** routes to your `config/routes.rb`:
67 | ```ruby
68 | mount Lecter::Engine => '/lecter' if Rails.env.development?
69 | ```
70 |
71 | ## :joystick: Usage
72 | Follow **two** simple steps:
73 |
74 | 1. **Go** to `/lecter`
75 |
76 | 2. **Fill in** the form fields with request parameters:
77 |
78 | `HTTP method` - request's method
79 | `Endpoint` - use absolute route like `localhost:3000/blogs`
80 | `Headers` - request's headers
81 | `Body(raw)` - request's parameters
82 |
83 | ## :man_technologist: Examples
84 | Here is an example with a **POST** request:
85 |
86 | 1. **Go** to `localhost:3000/lecter`
87 |
88 | 2. **Fill** in the form with:
89 |
90 | `HTTP method` - `POST`
91 | `Endpoint` - `localhost:3000/posts`
92 | `Headers` - `content_type=text/html,accept=*/*`
93 | `Body(raw)` - `"post"=>{"title"=>"New title", "description"=>"Desciption"}`
94 |
95 |
96 |
97 | 3. **Submit** the form
98 | 4. **Review** the result
99 |
100 |
101 |
102 | ## :heart: Sponsors
103 | [
][14]
104 |
105 | ## :desktop_computer: Contributing & Contributors
106 | 1. Bug reports and pull requests **are welcome**.
107 | 2. There are many issues as a proposal to improve this library. If you have any ideas, please **feel free** to write your thoughts in a [new issue][7].
108 | 3. Choose **what you like** to fix or improve on the [issues list][8]. You can ask any questions in the comments.
109 | 4. :bangbang: **Mention of each contributor** will be on the README file.
110 |
111 | **Thanks** goes to these wonderful people:
112 |
113 |
114 |
115 |
156 |
157 |
158 |
159 | ## :card_file_box: License
160 | The gem is available as open source under the terms of the [MIT License][9].
161 |
162 | [0]: https://badge.fury.io/rb/lecter.svg
163 | [1]: https://badge.fury.io/rb/lecter
164 | [2]: https://circleci.com/gh/Neodelf/lecter.svg?style=shield
165 | [3]: https://circleci.com/gh/neodelf/lecter
166 | [4]: https://github.com/puma/puma
167 | [5]: https://github.com/puma/puma#clustered-mode
168 | [7]: https://github.com/Neodelf/lecter/issues/new
169 | [8]: https://github.com/Neodelf/lecter/issues
170 | [9]: https://opensource.org/licenses/MIT
171 | [10]: https://api.codeclimate.com/v1/badges/45d57f439d66990490f1/maintainability
172 | [11]: https://codeclimate.com/github/Neodelf/lecter/maintainability
173 | [12]: https://api.codeclimate.com/v1/badges/45d57f439d66990490f1/test_coverage
174 | [13]: https://codeclimate.com/github/Neodelf/lecter/test_coverage
175 | [14]: https://evrone.com
176 | [15]: https://img.shields.io/badge/code_style-rubocop-brightgreen.svg
177 | [16]: https://rubystyle.guide
178 |
--------------------------------------------------------------------------------
/app/views/lecter/diagnosis/show.html.erb:
--------------------------------------------------------------------------------
1 | <%= content_for :title, t('.title') %>
2 |
3 |
4 |
<%= t('.executed_code') %>
5 |
6 |
7 |
8 |
21 |
22 |
23 |
24 | <% @file_listings.each_with_index do |file_listing, index| %>
25 |
26 |
34 |
35 |
36 |
37 | <% file_listing.html_rows.each do |html_row| %><%= raw(html_row) %><% end %>
38 |
39 |
40 |
41 |
42 | <% end %>
43 |
44 |
45 |
46 |
47 |
55 |
--------------------------------------------------------------------------------