core-extension 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e7e64f65a82f9721e0a0a39f85d8593e6b57e295d6cb8eb6c8febcc798c8497b
4
- data.tar.gz: e4d1dd2fea0b66d39a4c258c296a763c8d512b6404300a58c5f9d1dab66b67f0
3
+ metadata.gz: 02a2bc3087e71c3fc19d9f0c20210833a2a8bd88cf76f6187fade6e389eadf14
4
+ data.tar.gz: 8e38b249e3e3e5badcd6f9e6658d967f96f63ab837d563ca5e97f0cc408ee7a8
5
5
  SHA512:
6
- metadata.gz: d9c8dc64956983a80358ec5ed0dc8d7122029a2fc59750e1bacb3c84da0e81d44bec2958b82c2ae3f506a3c068e9e63b49cec8000e1ff0a9f7d021692b409bbc
7
- data.tar.gz: 1601c7edd515bd085ee5890ca0b4e3ce46b7920d594dbb9a806808da8c73549582ce7287926fa73de7abd4e662b87281a7c31a6b0ab22357fb52e09caf7f2502
6
+ metadata.gz: 38f391788aef874938c0e69dd95eaa24fee62737dbd5744a3bfafe0813e52189266ef079808a61d29c93688963b8eef1ef4bad9c38dbe2fcd38fb4ea468a3174
7
+ data.tar.gz: a41f51ba2b22432e4cd8505065f3e44fa57d1ba5c38cbc5c7b7fb362698cf47580dca2515b0b35fc0a2d2bd2fa5c498ab7faf1e7a67ada66f5591fb551d32954
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## [v0.3.0](https://github.com/metabahn/corerb/releases/tag/2021-07-15)
2
+
3
+ *released on 2021-07-15*
4
+
5
+ * `chg` [#72](https://github.com/metabahn/corerb/pull/72) Rename extension dependency flags ([bryanp](https://github.com/bryanp))
6
+ * `chg` [#71](https://github.com/metabahn/corerb/pull/71) Rename Is::Extension::applied to applies ([bryanp](https://github.com/bryanp))
7
+ * `chg` [#68](https://github.com/metabahn/corerb/pull/68) Pass the extension scope to apply blocks ([bryanp](https://github.com/bryanp))
8
+ * `chg` [#67](https://github.com/metabahn/corerb/pull/67) Refactor extend support for extensions ([bryanp](https://github.com/bryanp))
9
+ * `chg` [#66](https://github.com/metabahn/corerb/pull/66) Support extending classes with extensions ([bryanp](https://github.com/bryanp))
10
+
1
11
  ## [v0.2.0](https://github.com/metabahn/corerb/releases/tag/2021-07-07)
2
12
 
3
13
  *released on 2021-07-07*
@@ -12,9 +12,17 @@ module Core
12
12
  @module = build_module(&block)
13
13
  end
14
14
 
15
- # [public] Applies this behavior to an object.
15
+ # [public] Applies this behavior to an object via extend.
16
16
  #
17
- def apply(object)
17
+ def apply_extend(object)
18
+ if force? || unapplied?(object)
19
+ object.extend(@module)
20
+ end
21
+ end
22
+
23
+ # [public] Applies this behavior to an object via include.
24
+ #
25
+ def apply_include(object)
18
26
  if force? || unapplied?(object)
19
27
  object.include(@module)
20
28
  end
@@ -34,11 +42,35 @@ module Core
34
42
 
35
43
  private def build_module(&block)
36
44
  Module.new {
45
+ define_singleton_method(:extended) do |base|
46
+ arguments = {
47
+ extended: true,
48
+ included: false
49
+ }
50
+
51
+ base.class_exec(**Behavior.conditional_keyword_arguments(arguments, block), &block)
52
+ end
53
+
37
54
  define_singleton_method(:included) do |base|
38
- base.class_eval(&block)
55
+ arguments = {
56
+ extended: false,
57
+ included: true
58
+ }
59
+
60
+ base.class_exec(**Behavior.conditional_keyword_arguments(arguments, block), &block)
39
61
  end
40
62
  }
41
63
  end
64
+
65
+ class << self
66
+ def conditional_keyword_arguments(arguments, callable)
67
+ arguments.keep_if { |key, _value|
68
+ callable.parameters.any? { |type, name|
69
+ (type == :key || type == :keyreq || type == :keyrest) && name == key
70
+ }
71
+ }
72
+ end
73
+ end
42
74
  end
43
75
  end
44
76
  end
@@ -6,70 +6,71 @@ module Core
6
6
  #
7
7
  # flags - Changes how the dependencies are applied. Possible values include:
8
8
  #
9
- # * `:class` - Extends the including object, making methods available at the class level.
9
+ # * `:definition` - Extends the definition of the including object.
10
10
  #
11
- # * `:instance` - Includes the methods into the object, making them available at the instance level.
11
+ # * `:implementation` - Extends the implementation of the including object.
12
12
  #
13
- # Dependencies are applied with the `:instance` flag by default.
13
+ # Dependencies are applied with the `:implementation` flag by default.
14
14
  #
15
- # modules - Modules to be applied to objects, following the rules defined by flags.
15
+ # dependency - The dependency to be applied to objects, following the rules defined by flags.
16
16
  #
17
- # prepend - If `true`, methods will be prepended rather than appended.
18
- #
19
- # block - If passed, defines an anonymous module as a dependency.
17
+ # prepend - If `true`, methods will be prepended.
20
18
  #
21
19
  class Dependency
22
- ALLOWED_FLAGS = %i[class instance].freeze
20
+ ALLOWED_FLAGS = %i[definition implementation].freeze
21
+ ALLOWED_FLAGS_STRING = ALLOWED_FLAGS.map { |allowed_flag|
22
+ "`#{allowed_flag.inspect}'"
23
+ }.join(", ").freeze
23
24
 
24
- def initialize(*flags, modules: [], prepend: false, &block)
25
+ def initialize(*flags, dependency:, prepend: false)
25
26
  flags = flags.map(&:to_sym)
26
27
  enforce_allowed_flags(flags)
27
28
 
28
29
  @flags = flags
29
- @modules = modules.to_a
30
+ @dependency = dependency
30
31
  @prepend = prepend
31
-
32
- @modules << build_module(&block) if block
32
+ @definition = @flags.include?(:definition)
33
+ @implementation = @flags.include?(:implementation) || (!definition? && !prepend?)
33
34
  end
34
35
 
35
- # [public] Apply the defined dependencies to an object.
36
+ # [public] Apply the defined dependencies to an object via extend.
36
37
  #
37
- def apply(object)
38
- including = include?
39
- extending = extend?
40
- prepending = prepend?
38
+ def apply_extend(object)
39
+ if prepend?
40
+ object.singleton_class.prepend(@dependency) if implementation? || definition?
41
+ elsif definition? || implementation?
42
+ object.extend(@dependency)
43
+ end
44
+ end
41
45
 
42
- @modules.each do |each_module|
43
- if prepending
44
- object.prepend(each_module) if including
45
- object.singleton_class.prepend(each_module) if extending
46
- else
47
- object.include(each_module) if including
48
- object.extend(each_module) if extending
49
- end
46
+ # [public] Apply the defined dependencies to an object via include.
47
+ #
48
+ def apply_include(object)
49
+ if prepend?
50
+ object.prepend(@dependency) if implementation?
51
+ object.singleton_class.prepend(@dependency) if definition?
52
+ else
53
+ object.include(@dependency) if implementation?
54
+ object.extend(@dependency) if definition?
50
55
  end
51
56
  end
52
57
 
53
- private def include?
54
- @flags.include?(:instance) || (!extend? && !prepend?)
58
+ private def implementation?
59
+ @implementation == true
55
60
  end
56
61
 
57
- private def extend?
58
- @flags.include?(:class)
62
+ private def definition?
63
+ @definition == true
59
64
  end
60
65
 
61
66
  private def prepend?
62
67
  @prepend == true
63
68
  end
64
69
 
65
- private def build_module(&block)
66
- Module.new(&block)
67
- end
68
-
69
70
  private def enforce_allowed_flags(flags)
70
71
  flags.each do |flag|
71
72
  unless allowed_flag?(flag)
72
- raise ArgumentError, "Expected flag `#{flag.inspect}' to be one of: #{allowed_flags_string}"
73
+ raise ArgumentError, "Expected flag `#{flag.inspect}' to be one of: #{ALLOWED_FLAGS_STRING}"
73
74
  end
74
75
  end
75
76
  end
@@ -77,12 +78,6 @@ module Core
77
78
  private def allowed_flag?(flag)
78
79
  ALLOWED_FLAGS.include?(flag)
79
80
  end
80
-
81
- private def allowed_flags_string
82
- ALLOWED_FLAGS.map { |allowed_flag|
83
- "`#{allowed_flag.inspect}'"
84
- }.join(", ")
85
- end
86
81
  end
87
82
  end
88
83
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Core
4
4
  module Extension
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
 
7
7
  def self.version
8
8
  VERSION
data/lib/is/extension.rb CHANGED
@@ -15,20 +15,39 @@ module Is
15
15
 
16
16
  # [public] Define a module to be extended or included into objects that include this extension.
17
17
  #
18
+ # TODO: These flags almost need different names, since instance extensions could technically end up on a class.
19
+ # Name them by their intended use? Like a definition and usage lifecycle or something.
20
+ #
21
+ # Maybe `definition` and `implementation`?
22
+ #
18
23
  def extends(*flags, dependencies: [], prepend: false, &block)
19
- defined_methods << Core::Extension::Dependency.new(*flags, modules: dependencies, prepend: prepend, &block)
24
+ dependencies.each do |dependency|
25
+ defined_dependencies << Core::Extension::Dependency.new(*flags, dependency: dependency, prepend: prepend)
26
+ end
27
+
28
+ if block
29
+ defined_dependencies << Core::Extension::Dependency.new(*flags, dependency: Module.new(&block), prepend: prepend)
30
+ end
20
31
  end
21
32
 
22
33
  # [public] Define behavior to be evaled on objects that include this extension.
23
34
  #
24
- def applied(force: false, &block)
35
+ def applies(force: false, &block)
25
36
  defined_behaviors << Core::Extension::Behavior.new(force: force, &block)
26
37
  end
27
38
 
39
+ def extended(base)
40
+ enforce_allowed_types(base)
41
+ extend_defined_dependencies(base)
42
+ extend_defined_behaviors(base)
43
+
44
+ super
45
+ end
46
+
28
47
  def included(base)
29
48
  enforce_allowed_types(base)
30
- apply_defined_methods(base)
31
- apply_defined_behaviors(base)
49
+ include_defined_dependencies(base)
50
+ include_defined_behaviors(base)
32
51
 
33
52
  super
34
53
  end
@@ -51,15 +70,27 @@ module Is
51
70
  }
52
71
  end
53
72
 
54
- private def apply_defined_behaviors(object)
73
+ private def extend_defined_behaviors(object)
74
+ defined_behaviors.each do |behavior|
75
+ behavior.apply_extend(object)
76
+ end
77
+ end
78
+
79
+ private def extend_defined_dependencies(object)
80
+ defined_dependencies.each do |dependency|
81
+ dependency.apply_extend(object)
82
+ end
83
+ end
84
+
85
+ private def include_defined_behaviors(object)
55
86
  defined_behaviors.each do |behavior|
56
- behavior.apply(object)
87
+ behavior.apply_include(object)
57
88
  end
58
89
  end
59
90
 
60
- private def apply_defined_methods(object)
61
- defined_methods.each do |methods|
62
- methods.apply(object)
91
+ private def include_defined_dependencies(object)
92
+ defined_dependencies.each do |dependency|
93
+ dependency.apply_include(object)
63
94
  end
64
95
  end
65
96
 
@@ -71,8 +102,8 @@ module Is
71
102
  @__defined_behaviors ||= []
72
103
  end
73
104
 
74
- private def defined_methods
75
- @__defined_methods ||= []
105
+ private def defined_dependencies
106
+ @__defined_dependencies ||= []
76
107
  end
77
108
  end
78
109
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: core-extension
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryan Powell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-07 00:00:00.000000000 Z
11
+ date: 2021-07-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Create mixins with superpowers.
14
14
  email: bryan@metabahn.com