Introduce a LicenseTemplate model and LicenseTemplateFinder helper
This commit is contained in:
parent
ffd164d27f
commit
d3490f6998
4 changed files with 197 additions and 0 deletions
36
app/finders/license_template_finder.rb
Normal file
36
app/finders/license_template_finder.rb
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# LicenseTemplateFinder
|
||||||
|
#
|
||||||
|
# Used to find license templates, which may come from a variety of external
|
||||||
|
# sources
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# popular: boolean. When set to true, only "popular" licenses are shown. When
|
||||||
|
# false, all licenses except popular ones are shown. When nil (the
|
||||||
|
# default), *all* licenses will be shown.
|
||||||
|
class LicenseTemplateFinder
|
||||||
|
attr_reader :params
|
||||||
|
|
||||||
|
def initialize(params = {})
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
Licensee::License.all(featured: popular_only?).map do |license|
|
||||||
|
LicenseTemplate.new(
|
||||||
|
id: license.key,
|
||||||
|
name: license.name,
|
||||||
|
nickname: license.nickname,
|
||||||
|
category: (license.featured? ? :Popular : :Other),
|
||||||
|
content: license.content,
|
||||||
|
url: license.url,
|
||||||
|
meta: license.meta
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def popular_only?
|
||||||
|
params.fetch(:popular, nil)
|
||||||
|
end
|
||||||
|
end
|
53
app/models/license_template.rb
Normal file
53
app/models/license_template.rb
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
class LicenseTemplate
|
||||||
|
PROJECT_TEMPLATE_REGEX =
|
||||||
|
%r{[\<\{\[]
|
||||||
|
(project|description|
|
||||||
|
one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here
|
||||||
|
[\>\}\]]}xi.freeze
|
||||||
|
YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze
|
||||||
|
FULLNAME_TEMPLATE_REGEX =
|
||||||
|
%r{[\<\{\[]
|
||||||
|
(fullname|name\sof\s(author|copyright\sowner))
|
||||||
|
[\>\}\]]}xi.freeze
|
||||||
|
|
||||||
|
attr_reader :id, :name, :category, :nickname, :url, :meta
|
||||||
|
|
||||||
|
alias_method :key, :id
|
||||||
|
|
||||||
|
def initialize(id:, name:, category:, content:, nickname: nil, url: nil, meta: {})
|
||||||
|
@id = id
|
||||||
|
@name = name
|
||||||
|
@category = category
|
||||||
|
@content = content
|
||||||
|
@nickname = nickname
|
||||||
|
@url = url
|
||||||
|
@meta = meta
|
||||||
|
end
|
||||||
|
|
||||||
|
def popular?
|
||||||
|
category == :Popular
|
||||||
|
end
|
||||||
|
alias_method :featured?, :popular?
|
||||||
|
|
||||||
|
# Returns the text of the license
|
||||||
|
def content
|
||||||
|
if @content.respond_to?(:call)
|
||||||
|
@content = @content.call
|
||||||
|
else
|
||||||
|
@content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Populate placeholders in the LicenseTemplate content
|
||||||
|
def resolve!(project_name: nil, fullname: nil, year: Time.now.year.to_s)
|
||||||
|
# Ensure the string isn't shared with any other instance of LicenseTemplate
|
||||||
|
new_content = content.dup
|
||||||
|
new_content.gsub!(YEAR_TEMPLATE_REGEX, year) if year.present?
|
||||||
|
new_content.gsub!(PROJECT_TEMPLATE_REGEX, project_name) if project_name.present?
|
||||||
|
new_content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname.present?
|
||||||
|
|
||||||
|
@content = new_content
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
49
spec/finders/license_template_finder_spec.rb
Normal file
49
spec/finders/license_template_finder_spec.rb
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe LicenseTemplateFinder do
|
||||||
|
describe '#execute' do
|
||||||
|
subject(:result) { described_class.new(params).execute }
|
||||||
|
|
||||||
|
let(:categories) { categorised_licenses.keys }
|
||||||
|
let(:categorised_licenses) { result.group_by(&:category) }
|
||||||
|
|
||||||
|
context 'popular: true' do
|
||||||
|
let(:params) { { popular: true } }
|
||||||
|
|
||||||
|
it 'only returns popular licenses' do
|
||||||
|
expect(categories).to contain_exactly(:Popular)
|
||||||
|
expect(categorised_licenses[:Popular]).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'popular: false' do
|
||||||
|
let(:params) { { popular: false } }
|
||||||
|
|
||||||
|
it 'only returns unpopular licenses' do
|
||||||
|
expect(categories).to contain_exactly(:Other)
|
||||||
|
expect(categorised_licenses[:Other]).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'popular: nil' do
|
||||||
|
let(:params) { { popular: nil } }
|
||||||
|
|
||||||
|
it 'returns all licenses known by the Licensee gem' do
|
||||||
|
from_licensee = Licensee::License.all.map { |l| l.key }
|
||||||
|
|
||||||
|
expect(result.map(&:id)).to match_array(from_licensee)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'correctly copies all attributes' do
|
||||||
|
licensee = Licensee::License.all.first
|
||||||
|
found = result.find { |r| r.key == licensee.key }
|
||||||
|
|
||||||
|
aggregate_failures do
|
||||||
|
%i[key name content nickname url meta featured?].each do |k|
|
||||||
|
expect(found.public_send(k)).to eq(licensee.public_send(k))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
59
spec/models/license_template_spec.rb
Normal file
59
spec/models/license_template_spec.rb
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe LicenseTemplate do
|
||||||
|
describe '#content' do
|
||||||
|
it 'calls a proc exactly once if provided' do
|
||||||
|
lazy = build_template(-> { 'bar' })
|
||||||
|
content = lazy.content
|
||||||
|
|
||||||
|
expect(content).to eq('bar')
|
||||||
|
expect(content.object_id).to eq(lazy.content.object_id)
|
||||||
|
|
||||||
|
content.replace('foo')
|
||||||
|
expect(lazy.content).to eq('foo')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a string if provided' do
|
||||||
|
lazy = build_template('bar')
|
||||||
|
|
||||||
|
expect(lazy.content).to eq('bar')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#resolve!' do
|
||||||
|
let(:content) do
|
||||||
|
<<~TEXT
|
||||||
|
Pretend License
|
||||||
|
|
||||||
|
[project]
|
||||||
|
|
||||||
|
Copyright (c) [year] [fullname]
|
||||||
|
TEXT
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:expected) do
|
||||||
|
<<~TEXT
|
||||||
|
Pretend License
|
||||||
|
|
||||||
|
Foo Project
|
||||||
|
|
||||||
|
Copyright (c) 1985 Nick Thomas
|
||||||
|
TEXT
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:template) { build_template(content) }
|
||||||
|
|
||||||
|
it 'updates placeholders in a copy of the template content' do
|
||||||
|
expect(template.content.object_id).to eq(content.object_id)
|
||||||
|
|
||||||
|
template.resolve!(project_name: "Foo Project", fullname: "Nick Thomas", year: "1985")
|
||||||
|
|
||||||
|
expect(template.content).to eq(expected)
|
||||||
|
expect(template.content.object_id).not_to eq(content.object_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_template(content)
|
||||||
|
described_class.new(id: 'foo', name: 'foo', category: :Other, content: content)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue