Last active
January 20, 2022 05:43
-
-
Save ArtemBorodinEvgenyevich/01137c8b11ab25b533f30557e4763c90 to your computer and use it in GitHub Desktop.
Example of dsl annotation module
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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