Skip to content

Instantly share code, notes, and snippets.

@ArtemBorodinEvgenyevich
Last active January 20, 2022 05:43
Show Gist options
  • Select an option

  • Save ArtemBorodinEvgenyevich/01137c8b11ab25b533f30557e4763c90 to your computer and use it in GitHub Desktop.

Select an option

Save ArtemBorodinEvgenyevich/01137c8b11ab25b533f30557e4763c90 to your computer and use it in GitHub Desktop.
Example of dsl annotation module
# frozen_string_literal: true
module Validation
def self.validate_title(title)
stripped = title.strip
return stripped if stripped.length < 30
raise 'Title should be less than 30 chars.' if stripped.length > 30
end
def self.validate_score(score)
return score if (0..10) === (score)
raise 'Score is out of range: from 0 to 10.'
end
def self.validate_tag(tag)
return tag if tag.to_s.length < 15
raise 'Tag should be less than 15 chars.'
end
end
module Annotations
include Validation
def self.included(host_class)
host_class.extend(ClassMethods)
end
def title(value=nil)
if value.nil?
if defined? @title
@title
else
self.class.name
end
else
@title = Validation.validate_title(value)
end
end
def title=(value)
title(value)
end
def score(value=nil)
if value.nil?
if defined? @score
@score
else
self.class.score
end
else
@score = Validation.validate_score(value)
end
end
def score=(value)
score(value)
end
def tags(*values)
if values.empty?
if defined? @tags
@tags
else
self.class.tags
end
else
@tags = values.map { |value| Validation.validate_tag(value) }
end
end
alias_method :tag, :tags
module ClassMethods
def title(value=nil)
unless defined? @title
superclass_score = self.superclass.score if self.superclass.respond_to?(:title)
@title = superclass_score ? superclass_score : self.class.name
end
if value.nil?
@title
else
@title = Validation.validate_title(value)
end
end
def title=(value)
@title = title(value)
end
def score(value=nil)
unless defined? @score
superclass_score = self.superclass.score if self.superclass.respond_to?(:score)
@score = superclass_score ? superclass_score : 0
end
if value.nil?
@score
else
@score = Validation.validate_score(value)
end
end
def score=(value)
@score = score(value)
end
def tags(*values)
unless defined? @tags
superclass_tags = self.superclass.tags if self.superclass.respond_to?(:tags)
@tags = superclass_tags&.any? ? superclass_tags : []
end
if values.empty?
@tags
else
if self.superclass.respond_to?(:tags)
values.map { |value| Validation.validate_tag(value) }.each { |tag| @tags << tag}
else
@tags = values.map { |value| Validation.validate_tag(value) }
end
@tags
end
end
alias_method :tag, :tags
end
end
class Foo
include Annotations
score 4
title 'My cool title'
tags 'c', 'e'
end
require_relative '../dsl_annotations'
describe Annotations do
let(:dummy) { Foo.new }
before do
class Foo
include Annotations
title 'Foo title'
score 7
tags :x1, :x2
end
class Foo1 < Foo
end
class Foo2 < Foo
end
end
context 'when using class methods' do
it do
expect(Foo.title).to eq 'Foo title'
expect(Foo.title 'New title').to eq 'New title'
expect(Foo.score).to eq 7
expect(Foo.score 10).to eq 10
expect(Foo.tags).to eq [:x1, :x2]
expect(Foo.tags :c1, :c2).to eq [:c1, :c2]
expect(Foo.tag :y1).to eq [:y1]
expect(Foo.tag).to eq [:y1]
end
end
context 'when using instance methods' do
it do
expect(dummy.title).to eq 'Foo'
expect(dummy.title ' New title ').to eq 'New title'
expect(dummy.tags).to eq Foo.tags
expect(dummy.tag :y1).to eq [:y1]
expect(dummy.score).to eq Foo.score
expect(dummy.score 2).to eq 2
expect(dummy.score -= 1).to eq 1
end
end
context 'when redefine annotation' do
before { Foo.tags << 'tag1' }
it do
expect(dummy.tags).to eq [:x1, :x2, 'tag1']
expect(dummy.tags << 'tag2').to eq [:x1, :x2, 'tag1', 'tag2']
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment