DEV: Introduce syntax_tree for ruby formatting (#118)

This commit is contained in:
David Taylor 2022-12-29 12:31:34 +00:00 committed by GitHub
parent 3e489f8d1f
commit 724100044c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 177 additions and 155 deletions

View File

@ -55,3 +55,12 @@ jobs:
- name: Rubocop
if: ${{ !cancelled() }}
run: bundle exec rubocop .
- name: Syntax Tree
if: ${{ !cancelled() }}
run: |
if test -f .streerc; then
bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake')
else
echo "Stree config not detected for this repository. Skipping."
fi

View File

@ -80,7 +80,7 @@ jobs:
- name: Get yarn cache directory
id: yarn-cache-dir
run: echo "::set-output name=dir::$(yarn cache dir)"
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: Yarn cache
uses: actions/cache@v3
@ -130,7 +130,7 @@ jobs:
shell: bash
run: |
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/spec -type f -name "*.rb" 2> /dev/null | wc -l) ]; then
echo "::set-output name=files_exist::true"
echo "files_exist=true" >> $GITHUB_OUTPUT
fi
- name: Plugin RSpec
@ -142,7 +142,7 @@ jobs:
shell: bash
run: |
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/test/javascripts -type f \( -name "*.js" -or -name "*.es6" \) 2> /dev/null | wc -l) ]; then
echo "::set-output name=files_exist::true"
echo "files_exist=true" >> $GITHUB_OUTPUT
fi
- name: Plugin QUnit

View File

@ -1,2 +1,2 @@
inherit_gem:
rubocop-discourse: default.yml
rubocop-discourse: stree-compat.yml

2
.streerc Normal file
View File

@ -0,0 +1,2 @@
--print-width=100
--plugins=plugin/trailing_comma

View File

@ -1,7 +1,8 @@
# frozen_string_literal: true
source 'https://rubygems.org'
source "https://rubygems.org"
group :development do
gem 'rubocop-discourse'
gem "rubocop-discourse"
gem "syntax_tree"
end

View File

@ -6,6 +6,7 @@ GEM
parallel (1.22.1)
parser (3.1.2.1)
ast (~> 2.4.1)
prettier_print (1.2.0)
rainbow (3.1.1)
regexp_parser (2.6.0)
rexml (3.2.5)
@ -27,6 +28,8 @@ GEM
rubocop-rspec (2.13.2)
rubocop (~> 1.33)
ruby-progressbar (1.11.0)
syntax_tree (5.1.0)
prettier_print (>= 1.2.0)
unicode-display_width (2.3.0)
PLATFORMS
@ -34,6 +37,7 @@ PLATFORMS
DEPENDENCIES
rubocop-discourse
syntax_tree
BUNDLED WITH
2.3.4

View File

@ -2,7 +2,7 @@
module Docs
class DocsController < ApplicationController
requires_plugin 'docs'
requires_plugin "docs"
skip_before_action :check_xhr, only: [:index]
@ -15,7 +15,7 @@ module Docs
search_term: params[:search],
ascending: params[:ascending],
order: params[:order],
page: params[:page]
page: params[:page],
}
query = Docs::Query.new(current_user, filters).list
@ -23,12 +23,15 @@ module Docs
if filters[:topic].present?
begin
@topic = Topic.find(filters[:topic])
rescue
rescue StandardError
raise Discourse::NotFound
end
@excerpt = @topic.posts[0].excerpt(500, { strip_links: true, text_entities: true }) if @topic.posts[0].present?
@excerpt = (@excerpt || "").gsub(/\n/, ' ').strip
@excerpt =
@topic.posts[0].excerpt(500, { strip_links: true, text_entities: true }) if @topic.posts[
0
].present?
@excerpt = (@excerpt || "").gsub(/\n/, " ").strip
query["topic"] = get_topic(@topic, current_user)
end
@ -39,9 +42,7 @@ module Docs
render :get_topic
end
format.json do
render json: query
end
format.json { render json: query }
end
end
@ -65,9 +66,9 @@ module Docs
end
def set_title
title = "#{I18n.t('js.docs.title')} - #{SiteSetting.title}"
title = "#{I18n.t("js.docs.title")} - #{SiteSetting.title}"
if @topic
topic_title = @topic['unicode_title'] || @topic['title']
topic_title = @topic["unicode_title"] || @topic["title"]
title = "#{topic_title} - #{title}"
end
title

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require_dependency 'docs_constraint'
require_dependency "docs_constraint"
Docs::Engine.routes.draw do
get '/' => 'docs#index', constraints: DocsConstraint.new
get '.json' => 'docs#index', constraints: DocsConstraint.new
get "/" => "docs#index", :constraints => DocsConstraint.new
get ".json" => "docs#index", :constraints => DocsConstraint.new
end

View File

@ -7,7 +7,7 @@ module ::Docs
config.after_initialize do
Discourse::Application.routes.append do
mount ::Docs::Engine, at: "/#{GlobalSetting.docs_path}"
get '/knowledge-explorer', to: redirect("/#{GlobalSetting.docs_path}")
get "/knowledge-explorer", to: redirect("/#{GlobalSetting.docs_path}")
end
end
end

View File

@ -9,11 +9,11 @@ module Docs
end
def self.categories
SiteSetting.docs_categories.split('|')
SiteSetting.docs_categories.split("|")
end
def self.tags
SiteSetting.docs_tags.split('|')
SiteSetting.docs_tags.split("|")
end
def list
@ -23,11 +23,14 @@ module Docs
results = tq.list_docs_topics
results = results.left_outer_joins(:tags)
results = results.references(:categories)
results = results.where('topics.category_id IN (?)', Query.categories).or(results.where('tags.name IN (?)', Query.tags))
results =
results.where("topics.category_id IN (?)", Query.categories).or(
results.where("tags.name IN (?)", Query.tags),
)
# filter results by selected tags
if @filters[:tags].present?
tag_filters = @filters[:tags].split('|')
tag_filters = @filters[:tags].split("|")
tags_count = tag_filters.length
tag_filters = Tag.where_name(tag_filters).pluck(:id) unless Integer === tag_filters[0]
@ -35,7 +38,10 @@ module Docs
tag_filters.each_with_index do |tag, index|
# to_i to make it clear this is not an injection
sql_alias = "tt#{index.to_i}"
results = results.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}")
results =
results.joins(
"INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}",
)
end
else
results = results.none # don't return any results unless all tags exist in the database
@ -43,12 +49,15 @@ module Docs
end
if @filters[:solved].present?
results = results.where("topics.id IN (
results =
results.where(
"topics.id IN (
SELECT tc.topic_id
FROM topic_custom_fields tc
WHERE tc.name = 'accepted_answer_post_id' AND
tc.value IS NOT NULL
)")
)",
)
end
# filter results by search term
@ -73,15 +82,15 @@ module Docs
if @filters[:order] == "title"
if @filters[:ascending].present?
results = results.reorder('topics.title')
results = results.reorder("topics.title")
else
results = results.reorder('topics.title DESC')
results = results.reorder("topics.title DESC")
end
elsif @filters[:order] == "activity"
if @filters[:ascending].present?
results = results.reorder('topics.last_posted_at')
results = results.reorder("topics.last_posted_at")
else
results = results.reorder('topics.last_posted_at DESC')
results = results.reorder("topics.last_posted_at DESC")
end
end
@ -90,17 +99,25 @@ module Docs
INNER JOIN topic_tags ttx ON ttx.topic_id = topics.id
INNER JOIN tags t2 ON t2.id = ttx.tag_id
SQL
tags = count_query.group('t2.name').reorder('').count
tags = count_query.group("t2.name").reorder("").count
tags = create_tags_object(tags)
categories = results.where('topics.category_id IS NOT NULL').group('topics.category_id').reorder('').count
categories =
results
.where("topics.category_id IS NOT NULL")
.group("topics.category_id")
.reorder("")
.count
categories = create_categories_object(categories)
# filter results by selected category
# needs to be after building categories filter list
if @filters[:category].present?
category_ids = @filters[:category].split('|')
results = results.where('topics.category_id IN (?)', category_ids) if category_ids.all? { |id| id =~ /\A\d+\z/ }
category_ids = @filters[:category].split("|")
results =
results.where("topics.category_id IN (?)", category_ids) if category_ids.all? { |id|
id =~ /\A\d+\z/
}
end
results_length = results.size
@ -123,9 +140,9 @@ module Docs
topic_list = TopicListSerializer.new(topic_query, scope: Guardian.new(@user)).as_json
if end_of_list.nil?
topic_list['load_more_url'] = load_more_url
topic_list["load_more_url"] = load_more_url
else
topic_list['load_more_url'] = nil
topic_list["load_more_url"] = nil
end
{ tags: tags, categories: categories, topics: topic_list, topic_count: results_length }
@ -169,10 +186,10 @@ module Docs
if @filters[:page].present?
filters.push("page=#{@filters[:page].to_i + 1}")
else
filters.push('page=1')
filters.push("page=1")
end
"/#{GlobalSetting.docs_path}.json?#{filters.join('&')}"
"/#{GlobalSetting.docs_path}.json?#{filters.join("&")}"
end
end
end

View File

@ -9,44 +9,44 @@
enabled_site_setting :docs_enabled
register_asset 'stylesheets/common/docs.scss'
register_asset 'stylesheets/mobile/docs.scss'
register_asset "stylesheets/common/docs.scss"
register_asset "stylesheets/mobile/docs.scss"
register_svg_icon 'sort-alpha-down'
register_svg_icon 'sort-alpha-up'
register_svg_icon 'sort-numeric-up'
register_svg_icon 'sort-numeric-down'
register_svg_icon 'far-circle'
register_svg_icon "sort-alpha-down"
register_svg_icon "sort-alpha-up"
register_svg_icon "sort-numeric-up"
register_svg_icon "sort-numeric-down"
register_svg_icon "far-circle"
load File.expand_path('lib/docs/engine.rb', __dir__)
load File.expand_path('lib/docs/query.rb', __dir__)
load File.expand_path("lib/docs/engine.rb", __dir__)
load File.expand_path("lib/docs/query.rb", __dir__)
GlobalSetting.add_default :docs_path, "docs"
after_initialize do
require_dependency 'search'
require_dependency "search"
if SiteSetting.docs_enabled
if Search.respond_to? :advanced_filter
Search.advanced_filter(/in:(kb|docs)/) do |posts|
selected_categories = SiteSetting.docs_categories.split('|')
selected_categories = SiteSetting.docs_categories.split("|")
if selected_categories
categories = Category.where('id IN (?)', selected_categories).pluck(:id)
categories = Category.where("id IN (?)", selected_categories).pluck(:id)
end
selected_tags = SiteSetting.docs_tags.split('|')
if selected_tags
tags = Tag.where('name IN (?)', selected_tags).pluck(:id)
end
selected_tags = SiteSetting.docs_tags.split("|")
tags = Tag.where("name IN (?)", selected_tags).pluck(:id) if selected_tags
posts.where('category_id IN (?) OR topics.id IN (SELECT DISTINCT(tt.topic_id) FROM topic_tags tt WHERE tt.tag_id IN (?))', categories, tags)
posts.where(
"category_id IN (?) OR topics.id IN (SELECT DISTINCT(tt.topic_id) FROM topic_tags tt WHERE tt.tag_id IN (?))",
categories,
tags,
)
end
end
end
add_to_class(:topic_query, :list_docs_topics) do
default_results(@options)
end
add_to_class(:topic_query, :list_docs_topics) { default_results(@options) }
on(:robots_info) do |robots_info|
robots_info[:agents] ||= []
@ -61,7 +61,5 @@ after_initialize do
any_user_agent[:disallow] << "/#{GlobalSetting.docs_path}/"
end
add_to_serializer(:site, :docs_path) do
GlobalSetting.docs_path
end
add_to_serializer(:site, :docs_path) { GlobalSetting.docs_path }
end

View File

@ -1,122 +1,118 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
describe Docs::DocsController do
fab!(:category) { Fabricate(:category) }
fab!(:topic) { Fabricate(:topic, title: "I love carrot today", category: category) }
fab!(:topic2) { Fabricate(:topic, title: "I love pineapple today", category: category) }
fab!(:tag) { Fabricate(:tag, topics: [topic], name: 'test') }
fab!(:tag) { Fabricate(:tag, topics: [topic], name: "test") }
before do
SiteSetting.tagging_enabled = true
SiteSetting.docs_enabled = true
SiteSetting.docs_categories = category.id.to_s
SiteSetting.docs_tags = 'test'
GlobalSetting.stubs(:docs_path).returns('docs')
SiteSetting.docs_tags = "test"
GlobalSetting.stubs(:docs_path).returns("docs")
end
describe 'docs data' do
context 'when any user' do
it 'should return the right response' do
describe "docs data" do
context "when any user" do
it "should return the right response" do
get "/#{GlobalSetting.docs_path}.json"
expect(response.status).to eq(200)
json = JSON.parse(response.body)
tags = json['tags']
topics = json['topics']['topic_list']['topics']
tags = json["tags"]
topics = json["topics"]["topic_list"]["topics"]
expect(tags.size).to eq(1)
expect(topics.size).to eq(2)
end
it 'should return a topic count' do
it "should return a topic count" do
get "/#{GlobalSetting.docs_path}.json"
json = response.parsed_body
topic_count = json['topic_count']
topic_count = json["topic_count"]
expect(topic_count).to eq(2)
end
end
context 'when some docs topics are private' do
context "when some docs topics are private" do
let!(:group) { Fabricate(:group) }
let!(:private_category) { Fabricate(:private_category, group: group) }
let!(:private_topic) { Fabricate(:topic, category: private_category) }
before do
SiteSetting.docs_categories = "#{category.id}|#{private_category.id}"
end
before { SiteSetting.docs_categories = "#{category.id}|#{private_category.id}" }
it 'should not show topics in private categories without permissions' do
it "should not show topics in private categories without permissions" do
get "/#{GlobalSetting.docs_path}.json"
json = JSON.parse(response.body)
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
expect(topics.size).to eq(2)
end
it 'should show topics when users have permissions' do
it "should show topics when users have permissions" do
admin = Fabricate(:admin)
sign_in(admin)
get "/#{GlobalSetting.docs_path}.json"
json = JSON.parse(response.body)
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
expect(topics.size).to eq(3)
end
end
context 'when filtering by tag' do
fab!(:tag2) { Fabricate(:tag, topics: [topic], name: 'test2') }
fab!(:tag3) { Fabricate(:tag, topics: [topic], name: 'test3') }
context "when filtering by tag" do
fab!(:tag2) { Fabricate(:tag, topics: [topic], name: "test2") }
fab!(:tag3) { Fabricate(:tag, topics: [topic], name: "test3") }
it 'should return a list filtered by tag' do
it "should return a list filtered by tag" do
get "/#{GlobalSetting.docs_path}.json?tags=test"
expect(response.status).to eq(200)
json = JSON.parse(response.body)
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
expect(topics.size).to eq(1)
end
it 'should properly filter with more than two tags' do
it "should properly filter with more than two tags" do
get "/#{GlobalSetting.docs_path}.json?tags=test%7ctest2%7ctest3"
expect(response.status).to eq(200)
json = response.parsed_body
tags = json['tags']
topics = json['topics']['topic_list']['topics']
tags = json["tags"]
topics = json["topics"]["topic_list"]["topics"]
expect(tags.size).to eq(3)
expect(topics.size).to eq(1)
end
end
context 'when filtering by category' do
context "when filtering by category" do
let!(:category2) { Fabricate(:category) }
let!(:topic3) { Fabricate(:topic, category: category2) }
before do
SiteSetting.docs_categories = "#{category.id}|#{category2.id}"
end
before { SiteSetting.docs_categories = "#{category.id}|#{category2.id}" }
it 'should return a list filtered by category' do
it "should return a list filtered by category" do
get "/#{GlobalSetting.docs_path}.json?category=#{category2.id}"
expect(response.status).to eq(200)
json = JSON.parse(response.body)
categories = json['categories']
topics = json['topics']['topic_list']['topics']
categories = json["categories"]
topics = json["topics"]["topic_list"]["topics"]
expect(categories.size).to eq(2)
expect(categories[0]).to eq({ "active" => true, "count" => 1, "id" => category2.id })
@ -124,83 +120,78 @@ describe Docs::DocsController do
expect(topics.size).to eq(1)
end
it 'ignores category filter when incorrect argument' do
it "ignores category filter when incorrect argument" do
get "/#{GlobalSetting.docs_path}.json?category=hack"
expect(response.status).to eq(200)
json = JSON.parse(response.body)
categories = json['categories']
topics = json['topics']['topic_list']['topics']
categories = json["categories"]
topics = json["topics"]["topic_list"]["topics"]
expect(categories.size).to eq(2)
expect(topics.size).to eq(3)
end
end
context 'when ordering results' do
describe 'by title' do
it 'should return the list ordered descending' do
context "when ordering results" do
describe "by title" do
it "should return the list ordered descending" do
get "/#{GlobalSetting.docs_path}.json?order=title"
expect(response.status).to eq(200)
json = response.parsed_body
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
expect(topics[0]['id']).to eq(topic2.id)
expect(topics[1]['id']).to eq(topic.id)
expect(topics[0]["id"]).to eq(topic2.id)
expect(topics[1]["id"]).to eq(topic.id)
end
it 'should return the list ordered ascending with an additional parameter' do
it "should return the list ordered ascending with an additional parameter" do
get "/#{GlobalSetting.docs_path}.json?order=title&ascending=true"
expect(response.status).to eq(200)
json = response.parsed_body
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
expect(topics[0]['id']).to eq(topic.id)
expect(topics[1]['id']).to eq(topic2.id)
expect(topics[0]["id"]).to eq(topic.id)
expect(topics[1]["id"]).to eq(topic2.id)
end
end
describe 'by date' do
before do
topic2.update(last_posted_at: Time.zone.now + 100)
end
describe "by date" do
before { topic2.update(last_posted_at: Time.zone.now + 100) }
it 'should return the list ordered descending' do
it "should return the list ordered descending" do
get "/#{GlobalSetting.docs_path}.json?order=activity"
expect(response.status).to eq(200)
json = response.parsed_body
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
expect(topics[0]['id']).to eq(topic.id)
expect(topics[1]['id']).to eq(topic2.id)
expect(topics[0]["id"]).to eq(topic.id)
expect(topics[1]["id"]).to eq(topic2.id)
end
it 'should return the list ordered ascending with an additional parameter' do
it "should return the list ordered ascending with an additional parameter" do
get "/#{GlobalSetting.docs_path}.json?order=activity&ascending=true"
expect(response.status).to eq(200)
json = response.parsed_body
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
expect(topics[0]['id']).to eq(topic2.id)
expect(topics[1]['id']).to eq(topic.id)
expect(topics[0]["id"]).to eq(topic2.id)
expect(topics[1]["id"]).to eq(topic.id)
end
end
end
context 'when searching' do
before do
SearchIndexer.enable
end
context "when searching" do
before { SearchIndexer.enable }
# no fab here otherwise will be missing from search
let!(:post) do
@ -213,13 +204,13 @@ describe Docs::DocsController do
Fabricate(:post, topic: topic, raw: "I also eat bananas")
end
it 'should correctly filter topics' do
it "should correctly filter topics" do
get "/#{GlobalSetting.docs_path}.json?search=banana"
expect(response.status).to eq(200)
json = JSON.parse(response.body)
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
# ordered by latest for now
@ -231,53 +222,52 @@ describe Docs::DocsController do
get "/#{GlobalSetting.docs_path}.json?search=walk"
json = JSON.parse(response.body)
topics = json['topics']['topic_list']['topics']
topics = json["topics"]["topic_list"]["topics"]
expect(topics.size).to eq(1)
end
end
context 'when getting topic first post contents' do
context "when getting topic first post contents" do
let!(:non_ke_topic) { Fabricate(:topic) }
it 'should correctly grab the topic' do
it "should correctly grab the topic" do
get "/#{GlobalSetting.docs_path}.json?topic=#{topic.id}"
expect(response.parsed_body['topic']['id']).to eq(topic.id)
expect(response.parsed_body["topic"]["id"]).to eq(topic.id)
end
it 'should get topics matching a selected docs tag or category' do
it "should get topics matching a selected docs tag or category" do
get "/#{GlobalSetting.docs_path}.json?topic=#{non_ke_topic.id}"
expect(response.parsed_body['topic']).to be_blank
expect(response.parsed_body["topic"]).to be_blank
end
it 'should return a docs topic when only tags are added to settings' do
it "should return a docs topic when only tags are added to settings" do
SiteSetting.docs_categories = nil
get "/#{GlobalSetting.docs_path}.json?topic=#{topic.id}"
expect(response.parsed_body['topic']['id']).to eq(topic.id)
expect(response.parsed_body["topic"]["id"]).to eq(topic.id)
end
it 'should return a docs topic when only categories are added to settings' do
it "should return a docs topic when only categories are added to settings" do
SiteSetting.docs_tags = nil
get "/#{GlobalSetting.docs_path}.json?topic=#{topic.id}"
expect(response.parsed_body['topic']['id']).to eq(topic.id)
expect(response.parsed_body["topic"]["id"]).to eq(topic.id)
end
it 'should create TopicViewItem' do
it "should create TopicViewItem" do
admin = Fabricate(:admin)
sign_in(admin)
expect do
get "/#{GlobalSetting.docs_path}.json?topic=#{topic.id}"
end.to change { TopicViewItem.count }.by(1)
expect do get "/#{GlobalSetting.docs_path}.json?topic=#{topic.id}" end.to change {
TopicViewItem.count
}.by(1)
end
it 'should create TopicUser if authenticated' do
it "should create TopicUser if authenticated" do
expect do
get "/#{GlobalSetting.docs_path}.json?topic=#{topic.id}&track_visit=true"
end.not_to change { TopicUser.count }

View File

@ -1,17 +1,17 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
describe RobotsTxtController do
before do
SiteSetting.docs_enabled = true
GlobalSetting.stubs(:docs_path).returns('docs')
GlobalSetting.stubs(:docs_path).returns("docs")
end
it 'adds /docs/ to robots.txt' do
get '/robots.txt'
it "adds /docs/ to robots.txt" do
get "/robots.txt"
expect(response.body).to include('User-agent: *')
expect(response.body).to include("User-agent: *")
expect(response.body).to include("Disallow: /#{GlobalSetting.docs_path}/")
end
end

View File

@ -1,24 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
describe SiteSerializer do
fab!(:user) { Fabricate(:user) }
fab!(:user) { Fabricate(:user) }
let(:guardian) { Guardian.new(user) }
before do
SiteSetting.docs_enabled = true
GlobalSetting.stubs(:docs_path).returns('docs')
GlobalSetting.stubs(:docs_path).returns("docs")
end
it 'returns correct default value' do
it "returns correct default value" do
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(data[:docs_path]).to eq("docs")
end
it 'returns custom path based on global setting' do
GlobalSetting.stubs(:docs_path).returns('custom_path')
it "returns custom path based on global setting" do
GlobalSetting.stubs(:docs_path).returns("custom_path")
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(data[:docs_path]).to eq("custom_path")