annotable 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +23 -0
- data/.vscode/settings.json +14 -0
- data/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +85 -0
- data/README.md +95 -0
- data/Rakefile +37 -0
- data/annotable.gemspec +41 -0
- data/lib/annotable/annotation.rb +33 -0
- data/lib/annotable/method.rb +75 -0
- data/lib/annotable/version.rb +6 -0
- data/lib/annotable.rb +164 -0
- data/sig/annotable.rbs +168 -0
- metadata +147 -0
data/lib/annotable.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "annotable/annotation"
|
4
|
+
require_relative "annotable/method"
|
5
|
+
require_relative "annotable/version"
|
6
|
+
|
7
|
+
#
|
8
|
+
# Annotable is a module that can extend any class or module to add the ability to annotate its methods.
|
9
|
+
#
|
10
|
+
# class Needy
|
11
|
+
# extend Annotable # Extend your class or module with Annotable
|
12
|
+
# annotable :my_annotation, :my_other_annotation # Declare your annotations
|
13
|
+
#
|
14
|
+
# my_annotation 42, hello: "world!" # Annotate your methods
|
15
|
+
# def method_needing_meta_data
|
16
|
+
# # ...
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# def regular_method
|
20
|
+
# # ...
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# `Annotable` adds several methods to your class or module, providing access to annotations and their metadata:
|
25
|
+
#
|
26
|
+
# Needy.annotated_method_exist? :method_needing_meta_data # => true
|
27
|
+
# Needy.annotated_method_exist? :regular_method # => false
|
28
|
+
# Needy.annotated_methods
|
29
|
+
# # => [#<Annotable::Method
|
30
|
+
# # @annotations=[
|
31
|
+
# # #<Annotable::Annotation
|
32
|
+
# # @name=:my_annotation,
|
33
|
+
# # @options={:hello=>"world!"},
|
34
|
+
# # @params=[42]>
|
35
|
+
# # ],
|
36
|
+
# # @name=:method_needing_meta_data>
|
37
|
+
# # ]
|
38
|
+
#
|
39
|
+
# `Annotable::Method` represents a method name along with its annotations:
|
40
|
+
#
|
41
|
+
# method = Needy.annotated_methods.first
|
42
|
+
# method.name # => :method_needing_meta_data
|
43
|
+
# method.annotations
|
44
|
+
# # => [
|
45
|
+
# # #<Annotable::Annotation
|
46
|
+
# # @name=:my_annotation,
|
47
|
+
# # @options={:hello=>"world!"},
|
48
|
+
# # @params=[42]>
|
49
|
+
# # ]
|
50
|
+
#
|
51
|
+
# `Annotable::Annotation` contains annotation's name and metadata:
|
52
|
+
#
|
53
|
+
# annotation = method.annotations.first
|
54
|
+
# annotation.name # => :my_annotation
|
55
|
+
# annotation.params # => [42]
|
56
|
+
# annotation.options # => {:hello => "world!"}
|
57
|
+
#
|
58
|
+
module Annotable
|
59
|
+
#
|
60
|
+
# Declares annotations usable in the module or class.
|
61
|
+
#
|
62
|
+
# annotable :my_annotation, :my_other_annotation
|
63
|
+
#
|
64
|
+
# This will generate two class methods named after the given symbols.
|
65
|
+
# These methods, will push a new `Annotation` in the `current_annotation` array.
|
66
|
+
#
|
67
|
+
# @param [Array<Symbol>] annotation_names The names of annotations to declare
|
68
|
+
#
|
69
|
+
# @return [void]
|
70
|
+
#
|
71
|
+
def annotable(*annotation_names)
|
72
|
+
raise ArgumentError, "You must provide at least one annotation name" if annotation_names.empty?
|
73
|
+
|
74
|
+
annotation_names.each do |name|
|
75
|
+
define_singleton_method(name) do |*params, **options|
|
76
|
+
current_annotations.push Annotable::Annotation.new(name, params, options)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Return all annotated methods or those matching the given annotation names.
|
83
|
+
#
|
84
|
+
# @param [Array<Symbol>] names The annotation names to find
|
85
|
+
#
|
86
|
+
# @return [Array<Annotable::Method>] The annotated methods
|
87
|
+
#
|
88
|
+
def annotated_methods(*names)
|
89
|
+
return @annotated_methods if @annotated_methods.empty? || names.empty?
|
90
|
+
|
91
|
+
@annotated_methods.select do |method|
|
92
|
+
annotation_found = false
|
93
|
+
|
94
|
+
names.each do |name|
|
95
|
+
annotation_found = method.annotation_exist?(name)
|
96
|
+
break if annotation_found
|
97
|
+
end
|
98
|
+
|
99
|
+
annotation_found
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Check if an annotated method exists based in its name.
|
105
|
+
#
|
106
|
+
# @param [Symbol] name The name to check
|
107
|
+
#
|
108
|
+
# @return [Boolean] True if the annotated method exists, false otherwise
|
109
|
+
#
|
110
|
+
def annotated_method_exist?(name)
|
111
|
+
!annotated_methods.find { |am| am.name == name }.nil?
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
#
|
117
|
+
# A callback called by Ruby when a method is added into the class or module.
|
118
|
+
#
|
119
|
+
# @param [Symbol] name The name of the created method
|
120
|
+
#
|
121
|
+
# @return [void]
|
122
|
+
#
|
123
|
+
def method_added(name)
|
124
|
+
super
|
125
|
+
@annotated_methods ||= []
|
126
|
+
return if current_annotations.empty?
|
127
|
+
|
128
|
+
remove_annotated_method(name) if annotated_method_exist?(name)
|
129
|
+
@annotated_methods.push Annotable::Method.new(name, *current_annotations)
|
130
|
+
|
131
|
+
reset_current_annotations
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
# Remove an annotated method based on its name.
|
136
|
+
#
|
137
|
+
# @param [Symbol] name The name of the method to delete
|
138
|
+
#
|
139
|
+
# @return [void]
|
140
|
+
#
|
141
|
+
def remove_annotated_method(name)
|
142
|
+
@annotated_methods.reject! do |annotated_method|
|
143
|
+
annotated_method.name == name
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Annotation found for the current method declaration.
|
149
|
+
#
|
150
|
+
# @return [Array<Annotable::Annotation>] The annotations for the current method declaration
|
151
|
+
#
|
152
|
+
def current_annotations
|
153
|
+
@current_annotations ||= []
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Empty the current annotation array.
|
158
|
+
#
|
159
|
+
# @return [void]
|
160
|
+
#
|
161
|
+
def reset_current_annotations
|
162
|
+
@current_annotations = []
|
163
|
+
end
|
164
|
+
end
|
data/sig/annotable.rbs
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
#
|
2
|
+
# Annotable is a module that can extend any class or module to add the ability to annotate its methods.
|
3
|
+
#
|
4
|
+
# class Needy
|
5
|
+
# extend Annotable # Extend your class or module with Annotable
|
6
|
+
# annotable :my_annotation, :my_other_annotation # Declare your annotations
|
7
|
+
#
|
8
|
+
# my_annotation 42, hello: "world!" # Annotate your methods
|
9
|
+
# def method_needing_meta_data
|
10
|
+
# # ...
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# def regular_method
|
14
|
+
# # ...
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# `Annotable` adds several methods to your class or module, providing access to annotations and their metadata:
|
19
|
+
#
|
20
|
+
# Needy.annotated_method_exist? :method_needing_meta_data # => true
|
21
|
+
# Needy.annotated_method_exist? :regular_method # => false
|
22
|
+
# Needy.annotated_methods
|
23
|
+
# # => [#<Annotable::Method
|
24
|
+
# # @annotations=[
|
25
|
+
# # #<Annotable::Annotation
|
26
|
+
# # @name=:my_annotation,
|
27
|
+
# # @options={:hello=>"world!"},
|
28
|
+
# # @params=[42]>
|
29
|
+
# # ],
|
30
|
+
# # @name=:method_needing_meta_data>
|
31
|
+
# # ]
|
32
|
+
#
|
33
|
+
# `Annotable::Method` represents a method name along with its annotations:
|
34
|
+
#
|
35
|
+
# method = Needy.annotated_methods.first
|
36
|
+
# method.name # => :method_needing_meta_data
|
37
|
+
# method.annotations
|
38
|
+
# # => [
|
39
|
+
# # #<Annotable::Annotation
|
40
|
+
# # @name=:my_annotation,
|
41
|
+
# # @options={:hello=>"world!"},
|
42
|
+
# # @params=[42]>
|
43
|
+
# # ]
|
44
|
+
#
|
45
|
+
# `Annotable::Annotation` contains annotation's name and metadata:
|
46
|
+
#
|
47
|
+
# annotation = method.annotations.first
|
48
|
+
# annotation.name # => :my_annotation
|
49
|
+
# annotation.params # => [42]
|
50
|
+
# annotation.options # => {:hello => "world!"}
|
51
|
+
module Annotable
|
52
|
+
VERSION: String
|
53
|
+
|
54
|
+
# Declares annotations usable in the module or class.
|
55
|
+
#
|
56
|
+
# annotable :my_annotation, :my_other_annotation
|
57
|
+
#
|
58
|
+
# This will generate two class methods named after the given symbols.
|
59
|
+
# These methods, will push a new `Annotation` in the `current_annotation` array.
|
60
|
+
#
|
61
|
+
# _@param_ `annotation_names` — The names of annotations to declare
|
62
|
+
def annotable: (*::Array[Symbol] annotation_names) -> void
|
63
|
+
|
64
|
+
# Return all annotated methods or those matching the given annotation names.
|
65
|
+
#
|
66
|
+
# _@param_ `names` — The annotation names to find
|
67
|
+
#
|
68
|
+
# _@return_ — The annotated methods
|
69
|
+
def annotated_methods: (*::Array[Symbol] names) -> ::Array[Annotable::Method]
|
70
|
+
|
71
|
+
# Check if an annotated method exists based in its name.
|
72
|
+
#
|
73
|
+
# _@param_ `name` — The name to check
|
74
|
+
#
|
75
|
+
# _@return_ — True if the annotated method exists, false otherwise
|
76
|
+
def annotated_method_exist?: (Symbol name) -> bool
|
77
|
+
|
78
|
+
# A callback called by Ruby when a method is added into the class or module.
|
79
|
+
#
|
80
|
+
# _@param_ `name` — The name of the created method
|
81
|
+
def method_added: (Symbol name) -> void
|
82
|
+
|
83
|
+
# Remove an annotated method based on its name.
|
84
|
+
#
|
85
|
+
# _@param_ `name` — The name of the method to delete
|
86
|
+
def remove_annotated_method: (Symbol name) -> void
|
87
|
+
|
88
|
+
# Annotation found for the current method declaration.
|
89
|
+
#
|
90
|
+
# _@return_ — The annotations for the current method declaration
|
91
|
+
def current_annotations: () -> ::Array[Annotable::Annotation]
|
92
|
+
|
93
|
+
# Empty the current annotation array.
|
94
|
+
def reset_current_annotations: () -> void
|
95
|
+
|
96
|
+
#
|
97
|
+
# An annotated method with its annotations.
|
98
|
+
#
|
99
|
+
# one = Annotation.new(:one)
|
100
|
+
# two = Annotation.new(:two)
|
101
|
+
# some_method = Method.new(:some_method, one, two)
|
102
|
+
#
|
103
|
+
# some_method.annotation_exist?(:one) # => true
|
104
|
+
# some_method.annotation_exist?(:no) # => false
|
105
|
+
# some_method.select_annotations(:one) # => [#<Annotable::Annotation @name=:one, @options={}, @params=[]>]
|
106
|
+
class Method
|
107
|
+
# Creates a new annotated method.
|
108
|
+
#
|
109
|
+
# _@param_ `name` — The method name
|
110
|
+
#
|
111
|
+
# _@param_ `annotations` — The annotations linked to this method
|
112
|
+
def initialize: (Symbol name, *::Array[Annotation] annotations) -> void
|
113
|
+
|
114
|
+
# Determines whether annotation exists based on its name.
|
115
|
+
#
|
116
|
+
# _@param_ `name` — The annotation's name to check for
|
117
|
+
#
|
118
|
+
# _@return_ — True if the annotation exists, false otherwise
|
119
|
+
def annotation_exist?: (Symbol name) -> bool
|
120
|
+
|
121
|
+
# Returns all annotations matching the given names.
|
122
|
+
#
|
123
|
+
# _@param_ `names` — Names of the annotations to select
|
124
|
+
#
|
125
|
+
# _@return_ — The matching annotations
|
126
|
+
def select_annotations: (*::Array[Symbol] names) -> ::Array[Annotation]
|
127
|
+
|
128
|
+
# Finds the first annotation matching one of the given names.
|
129
|
+
#
|
130
|
+
# _@param_ `*names` — The annotation names to find
|
131
|
+
#
|
132
|
+
# _@return_ — The matching annotation
|
133
|
+
def find_annotation: (*::Array[Symbol] names) -> Annotation
|
134
|
+
|
135
|
+
# _@return_ — The method name
|
136
|
+
attr_reader name: Symbol
|
137
|
+
|
138
|
+
# _@return_ — The annotations declared for this method
|
139
|
+
attr_reader annotations: ::Array[Annotation]
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Encapsulates annotation data: name, params & options.
|
144
|
+
#
|
145
|
+
# my_annotation = Annotation.new(:name, ["some", "params"], {some: "options"})
|
146
|
+
# my_annotation.name # => :name
|
147
|
+
# my_annotation.params # => ["some", "params"]
|
148
|
+
# my_annotation.options # => {some: "options"}
|
149
|
+
class Annotation
|
150
|
+
# Creates an new annotation.
|
151
|
+
#
|
152
|
+
# _@param_ `name` — The annotation's name
|
153
|
+
#
|
154
|
+
# _@param_ `params` — The annotation's params
|
155
|
+
#
|
156
|
+
# _@param_ `options` — The annotation's options
|
157
|
+
def initialize: (Symbol name, ?::Array[Object] params, ?::Hash[Symbol, Object] options) -> void
|
158
|
+
|
159
|
+
# _@return_ — The annotation's name
|
160
|
+
attr_reader name: Symbol
|
161
|
+
|
162
|
+
# _@return_ — The annotation's params
|
163
|
+
attr_reader params: ::Array[Object]
|
164
|
+
|
165
|
+
# _@return_ — The annotation's options
|
166
|
+
attr_reader options: ::Hash[Symbol, Object]
|
167
|
+
end
|
168
|
+
end
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: annotable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mathieu MOREL
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-03-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '13.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '13.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.11'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.29'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.29'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop-rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.11'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.11'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.21'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.21'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sord
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4.0'
|
97
|
+
description: Provides a simple way to add annotations to your method declarations.
|
98
|
+
email:
|
99
|
+
- mathieu@lamanufacture.dev
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".rspec"
|
105
|
+
- ".rubocop.yml"
|
106
|
+
- ".vscode/settings.json"
|
107
|
+
- COPYING
|
108
|
+
- COPYING.LESSER
|
109
|
+
- Gemfile
|
110
|
+
- Gemfile.lock
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- annotable.gemspec
|
114
|
+
- lib/annotable.rb
|
115
|
+
- lib/annotable/annotation.rb
|
116
|
+
- lib/annotable/method.rb
|
117
|
+
- lib/annotable/version.rb
|
118
|
+
- sig/annotable.rbs
|
119
|
+
homepage: https://github.com/ductr-io/annotable
|
120
|
+
licenses:
|
121
|
+
- LGPL-3.0-or-later
|
122
|
+
metadata:
|
123
|
+
allowed_push_host: https://rubygems.org
|
124
|
+
rubygems_mfa_required: 'true'
|
125
|
+
homepage_uri: https://github.com/ductr-io/annotable
|
126
|
+
source_code_uri: https://github.com/ductr-io/annotable
|
127
|
+
changelog_uri: https://github.com/ductr-io/annotable/releases
|
128
|
+
post_install_message:
|
129
|
+
rdoc_options: []
|
130
|
+
require_paths:
|
131
|
+
- lib
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 3.1.0
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
requirements: []
|
143
|
+
rubygems_version: 3.3.26
|
144
|
+
signing_key:
|
145
|
+
specification_version: 4
|
146
|
+
summary: A simple zero-dependency method annotation gem
|
147
|
+
test_files: []
|