gemmyrb 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3738de0bcb6474f41bc2f0959d5fc57c056e1c2d
4
- data.tar.gz: 6d5a3339c10b4ecd92e29d4f380b66f536748756
3
+ metadata.gz: 57241faae027cf6e4416104dcedd95dcdb6f3d56
4
+ data.tar.gz: 6f4caf998b97cd0e9fdc84f243f19813248e0541
5
5
  SHA512:
6
- metadata.gz: f9afef465e6795c1e168dda4178c1cf77d45508f9069e279891ee022b08cd27ac64390de49ada10978ab494898bdad6b1c3a8f67ce24c6b62154e8a5ec4484de
7
- data.tar.gz: f5183dea0d4e286ac33bffa45d060d379b0ddf3c108e098d8f8c408cf0b6ae67a2b7e5497519fb20ea7496df8be53ad47ca5e9e8a426c68807ae18aa16787718
6
+ metadata.gz: 2fef2f0b535f1829842689b3c6d5dc92cbf223dac26ea3b0dceb60476a075309e59e3ee3be8e25b93b198734bc2e8c15f8c3a5030cfb4cb21a832fb13ddc51d5
7
+ data.tar.gz: ce6f3a3f1c5d7b54eac6e72fc1341bf3748a6926bc054cda10d6512e7905a22ca87d291ddd6c6dc8a485e70fb05750c42c1b0b6bc7a14e7a44125190bc16c4f3
data/README.md CHANGED
@@ -22,4 +22,4 @@ documents:
22
22
  - _List of methods intended for general Ruby use_
23
23
  - [examples/03_ruby_extensions_list.rb](./examples/03_ruby_extensions_list.rb)
24
24
  - _Shell commands and other one-off processes_
25
- - [examples/04_shell_commands.rb](./04_shell_commands.rb)
25
+ - [examples/04_shell_commands.rb](./examples/04_shell_commands.rb)
data/lib/gemmy/cli.rb CHANGED
@@ -14,7 +14,7 @@ class Gemmy::CLI < Thor
14
14
  def self.run(arguments: nil)
15
15
  # Store a copy of the arguments.
16
16
  # The originals are shifted so they don't intefere with gets
17
- arguments = ARGV.clone
17
+ arguments ||= ARGV.clone
18
18
  ARGV.clear
19
19
 
20
20
  # Can't make this conditional on "__FILE__ == $0"
@@ -19,7 +19,7 @@
19
19
  #
20
20
  module Gemmy::Components::DynamicSteps
21
21
 
22
- Gemmy::Patches.refinements.each { |r| using r }
22
+ Gemmy::Patches.class_refinements.each { |r| using r }
23
23
 
24
24
  # Error raised when a string matches multiple step regexes.
25
25
  # It's frequently accidental to come into this situation,
@@ -9,7 +9,7 @@
9
9
  end
10
10
 
11
11
  def self.list
12
- [
12
+ @@list ||= [
13
13
  Gemmy::Components::DynamicSteps
14
14
  ]
15
15
  end
@@ -1,19 +1,191 @@
1
1
  # Array patches
2
2
  #
3
3
  module Gemmy::Patches::ArrayPatch
4
- # checks if any of the results of an array do not respond truthily
5
- # to a block
6
- #
7
- # For example, to check if any items of an array are truthy:
8
- # [false, nil, ''].any_not? &:blank?
9
- # => false
10
- #
11
- def any_not?(&blk)
12
- any? { |item| ! blk.call(item) }
4
+
5
+ module ClassMethods
6
+
7
+ module Zip
8
+ # facets
9
+ def self.zip(*arrays)
10
+ return [] if arrays.empty?
11
+ return arrays[0].zip(*arrays[1..-1])
12
+ end
13
+ end
14
+
13
15
  end
14
16
 
15
- refine Array do
16
- include Gemmy::Patches::ArrayPatch
17
+ module InstanceMethods
18
+
19
+ module KeyBy
20
+ # facets
21
+ def key_by
22
+ return to_enum(:key_by) unless block_given?
23
+ h = {}
24
+ each do |v|
25
+ h[yield(v)] = v
26
+ end
27
+ return h
28
+ end
29
+ end
30
+
31
+ module After
32
+ # facets
33
+ def after(value)
34
+ return nil unless include? value
35
+ self[(index(value).to_i + 1) % length]
36
+ end
37
+ end
38
+
39
+ module Before
40
+ # facets
41
+ def before(value)
42
+ return nil unless include? value
43
+ self[(index(value).to_i - 1) % length]
44
+ end
45
+ end
46
+
47
+ module Duplicates
48
+ # facets
49
+ def duplicates(min=2)
50
+ h = Hash.new( 0 )
51
+ each {|i|
52
+ h[i] += 1
53
+ }
54
+ h.delete_if{|_,v| v < min}.keys
55
+ end
56
+ end
57
+
58
+ module ExtractOptions
59
+ # facets
60
+ def extract_options!
61
+ if Hash === last && last.extractable_options?
62
+ pop
63
+ else
64
+ {}
65
+ end
66
+ end
67
+ end
68
+
69
+ module RejectValues
70
+ # facets
71
+ def reject_values(*values)
72
+ reject { |x| values.include?(x) }
73
+ end
74
+ end
75
+
76
+ module Recurse
77
+ # facets
78
+ def recurse(*types, &block)
79
+ types = [self.class] if types.empty?
80
+ a = inject([]) do |array, value|
81
+ case value
82
+ when *types
83
+ array << value.recurse(*types, &block)
84
+ else
85
+ array << value
86
+ end
87
+ array
88
+ end
89
+ yield a
90
+ end
91
+ end
92
+
93
+ module Probability
94
+ # facets
95
+ def probability
96
+ probs = Hash.new(0.0)
97
+ size = 0.0
98
+ each do |e|
99
+ probs[e] += 1.0
100
+ size += 1.0
101
+ end
102
+ probs.keys.each{ |e| probs[e] /= size }
103
+ probs
104
+ end
105
+ end
106
+
107
+ module NotEmpty
108
+ # facets
109
+ def not_empty?
110
+ !empty?
111
+ end
112
+ end
113
+
114
+ module Median
115
+ # facets
116
+ def median(offset=0)
117
+ return nil if self.size == 0
118
+
119
+ tmp = self.sort
120
+ mid = (tmp.size / 2).to_i + offset
121
+
122
+ tmp[mid]
123
+ end
124
+ end
125
+
126
+ module Mode
127
+ # facets
128
+ def mode
129
+ max = 0
130
+ c = Hash.new 0
131
+ each {|x| cc = c[x] += 1; max = cc if cc > max}
132
+ c.select {|k,v| v == max}.map {|k,v| k}
133
+ end
134
+ end
135
+
136
+ module NonUniq
137
+
138
+ # facets
139
+ def nonuniq
140
+ h1 = {}
141
+ h2 = {}
142
+ each {|i|
143
+ h2[i] = true if h1[i]
144
+ h1[i] = true
145
+ }
146
+ h2.keys
147
+ end
148
+ end
149
+
150
+ module Arrange
151
+ # facets
152
+ # creates ranges from array
153
+ def arrange
154
+ array = uniq.sort_by { |e| Range === e ? e.first : e }
155
+ array.inject([]) do |c, value|
156
+ unless c.empty?
157
+ last = c.last
158
+ last_value = (Range === last ? last.last : last)
159
+ current_value = (Range === value ? value.first : value)
160
+ if (last_value.succ <=> current_value) == -1
161
+ c << value
162
+ else
163
+ first = (Range === last ? last.first : last)
164
+ second = [Range === last ? last.last : last, Range === value ? value.last : value].max
165
+ c[-1] = [first..second]
166
+ c.flatten!
167
+ end
168
+ else
169
+ c << value
170
+ end
171
+ end
172
+ end
173
+ alias rangify arrange
174
+ end
175
+
176
+ module AnyNot
177
+ # checks if any of the results of an array do not respond truthily
178
+ # to a block
179
+ #
180
+ # For example, to check if any items of an array are truthy:
181
+ # [false, nil, ''].any_not? &:blank?
182
+ # => false
183
+ #
184
+ def any_not?(&blk)
185
+ any? { |item| ! blk.call(item) }
186
+ end
187
+ end
188
+
17
189
  end
18
190
 
19
191
  end
@@ -2,85 +2,100 @@
2
2
  #
3
3
  module Gemmy::Patches::HashPatch
4
4
 
5
- # The opposite of Hash#dig
6
- # Takes a list of keys followed by a value to set
7
- #
8
- # Example:
9
- #
10
- # a = {a: {b: {}} }
11
- # a.bury(:a, :b, :c, 0)
12
- # puts a[:a][:b][:c]
13
- # => 0
14
- #
15
- # Source: https://github.com/dam13n/ruby-bury/blob/master/hash.rb
16
- #
17
- def bury *args
18
- Gemmy::Patches::HashPatch._bury(self, *args)
5
+ module ClassMethods
19
6
  end
20
7
 
21
- # The bury method, taking the input hash as a parameter
22
- # Used by the Hash#bury instance method
23
- def self._bury(caller_hash, *args)
24
- if args.count < 2
25
- raise ArgumentError.new("2 or more arguments required")
26
- elsif args.count == 2
27
- caller_hash[args[0]] = args[1]
28
- else
29
- arg = args.shift
30
- caller_hash[arg] = {} unless caller_hash[arg]
31
- _bury(caller_hash[arg], *args) unless args.empty?
8
+ module InstanceMethods
9
+
10
+ # The opposite of Hash#dig
11
+ # Takes a list of keys followed by a value to set
12
+ #
13
+ # Example:
14
+ #
15
+ # a = {a: {b: {}} }
16
+ # a.bury(:a, :b, :c, 0)
17
+ # puts a[:a][:b][:c]
18
+ # => 0
19
+ #
20
+ # Source: https://github.com/dam13n/ruby-bury/blob/master/hash.rb
21
+ #
22
+ module Bury
23
+ def bury *args
24
+ Gemmy::Patches::HashPatch::InstanceMethods::Bury._bury(self, *args)
25
+ end
26
+ # The bury method, taking the input hash as a parameter
27
+ # Used by the Hash#bury instance method
28
+ def self._bury(caller_hash, *args)
29
+ if args.count < 2
30
+ raise ArgumentError.new("2 or more arguments required")
31
+ elsif args.count == 2
32
+ caller_hash[args[0]] = args[1]
33
+ else
34
+ arg = args.shift
35
+ caller_hash[arg] = {} unless caller_hash[arg]
36
+ _bury(caller_hash[arg], *args) unless args.empty?
37
+ end
38
+ caller_hash
39
+ end
32
40
  end
33
- caller_hash
34
- end
35
41
 
36
- # Turns a hash into one that's "autovivified"
37
- # meaning it's default values for keys is an empty hash.
38
- # The result is that you can set nested keys without initializing
39
- # more than one hash layer.
40
- #
41
- # Usage:
42
- # hash = {}.autovivified
43
- # hash[:a][:b] = 0
44
- # puts hash[:a][:b]
45
- # => 0
46
- #
47
- def autovivified
48
- Gemmy::Patches::HashPatch._autovivified(self)
49
- end
42
+ # Turns a hash into one that's "autovivified"
43
+ # meaning it's default values for keys is an empty hash.
44
+ # The result is that you can set nested keys without initializing
45
+ # more than one hash layer.
46
+ #
47
+ # Usage:
48
+ # hash = {}.autovivified
49
+ # hash[:a][:b] = 0
50
+ # puts hash[:a][:b]
51
+ # => 0
52
+ #
53
+ module Autovivified
54
+ def self._autovivified(caller_hash)
55
+ result = Hash.new do |hash,key|
56
+ hash[key] = Hash.new(&hash.default_proc)
57
+ end
58
+ result.deep_merge caller_hash
59
+ end
60
+ def autovivified
61
+ Gemmy::Patches::HashPatch::InstanceMethods::Autovivified._autovivified(self)
62
+ end
63
+ end
50
64
 
51
- def self._autovivified(caller_hash)
52
- result = Hash.new { |hash,key| hash[key] = Hash.new(&hash.default_proc) }
53
- result.deep_merge caller_hash
54
- end
65
+ # Sets up a hash to mirror all changes to a database file
66
+ # All nested gets & sets require a list of keys, passed as subsequent args.
67
+ # Instead of [] and []=, use get and set
68
+ #
69
+ # Everything in the db is contained in a hash with one predefined
70
+ # key, :data. The value is an empty, autovivified hash.
71
+ #
72
+ # This also makes the caller hash autovivified
73
+ #
74
+ # Example:
75
+ #
76
+ # hash = {}.persisted("db.yaml")
77
+ # hash.set(:a, :b, 0) # => this writes to disk and memory
78
+ # hash.get(:a, :b) # => reads from memory
79
+ # hash.get(:a, :b, disk: true) # => reads from disk
80
+ #
55
81
 
56
- # Sets up a hash to mirror all changes to a database file
57
- # All nested gets & sets require a list of keys, passed as subsequent args.
58
- # Instead of [] and []=, use get and set
59
- #
60
- # Everything in the db is contained in a hash with one predefined
61
- # key, :data. The value is an empty, autovivified hash.
62
- #
63
- # This also makes the caller hash autovivified
64
- #
65
- # Example:
66
- #
67
- # hash = {}.persisted("db.yaml")
68
- # hash.set(:a, :b, 0) # => this writes to disk and memory
69
- # hash.get(:a, :b) # => reads from memory
70
- # hash.get(:a, :b, disk: true) # => reads from disk
71
- #
72
- def persisted(path)
73
- require 'yaml/store'
74
- Gemmy::Patches::HashPatch._autovivified(self).tap do |hash|
75
- hash.instance_exec do
76
- @db = YAML::Store.new path
77
- @db.transaction do
78
- @db[:data] = Gemmy::Patches::HashPatch._autovivified({})
82
+ module Persisted
83
+ def persisted(path)
84
+ require 'yaml/store'
85
+ autovivified = Gemmy::Patches::HashPatch::InstanceMethods::Autovivified.method(:_autovivified)
86
+ autovivified.call(self).tap do |hash|
87
+ hash.instance_exec do
88
+ @db = YAML::Store.new path
89
+ @db.transaction do
90
+ @db[:data] = autovivified.call({})
91
+ end
92
+ end
93
+ hash.extend Gemmy::Patches::HashPatch::PersistedHash
79
94
  end
80
95
  end
81
- hash.extend Gemmy::Patches::HashPatch::PersistedHash
82
96
  end
83
- end
97
+
98
+ end # end instance methods
84
99
 
85
100
  # Helper methods for the persistence patch
86
101
  #
@@ -89,16 +104,13 @@ module Gemmy::Patches::HashPatch
89
104
  disk ? @db.transaction { @db[:data].dig(*keys) } : dig(*keys)
90
105
  end
91
106
  def set(*keys, val)
92
- Gemmy::Patches::HashPatch._bury(self, *keys, val)
107
+ bury = Gemmy::Patches::HashPatch::InstanceMethods::Bury.method(:_bury)
108
+ bury.call(self, *keys, val)
93
109
  @db.transaction do
94
- Gemmy::Patches::HashPatch._bury(@db[:data], *(keys + [val]))
110
+ bury.call(@db[:data], *(keys + [val]))
95
111
  end
96
112
  val
97
113
  end
98
114
  end
99
115
 
100
- refine Hash do
101
- include Gemmy::Patches::HashPatch
102
- end
103
-
104
116
  end
@@ -0,0 +1,53 @@
1
+ module Gemmy::Patches::IntegerPatch
2
+
3
+ module ClassMethods
4
+
5
+ end
6
+
7
+ module InstanceMethods
8
+
9
+ module Factorial
10
+ # facets
11
+ def factorial
12
+ return 1 if zero?
13
+ f = 1
14
+ 2.upto(self) { |n| f *= n }
15
+ f
16
+ end
17
+ end
18
+
19
+ module MultipleOf
20
+ # facets
21
+ def multiple_of?(number)
22
+ if number.zero?
23
+ zero? ? true : false
24
+ else
25
+ self % number == 0
26
+ end
27
+ end
28
+ end
29
+
30
+ module Odd
31
+ def odd?
32
+ ! even?
33
+ end
34
+ end
35
+
36
+ module Of
37
+ # facets
38
+ def of(&block)
39
+ Array.new(self, &block)
40
+ end
41
+ alias times_map of
42
+ end
43
+
44
+ module Collapse
45
+ # facets
46
+ def collapse
47
+ flatten.compact
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -2,21 +2,26 @@
2
2
  #
3
3
  module Gemmy::Patches::MethodPatch
4
4
 
5
- # Bind an argument to a method.
6
- # Very useful for the proc shorthand.
7
- # For example say there's a method "def add(a,b); print a + b; end"
8
- # You can run it for each number in a list:
9
- # [1,2,3].each &method(:add).bind(1)
10
- # => 234
11
- #
12
- def bind *args
13
- Proc.new do |*more|
14
- self.call *(args + more)
15
- end
5
+ module ClassMethods
16
6
  end
17
7
 
18
- refine Method do
19
- include Gemmy::Patches::MethodPatch
8
+ module InstanceMethods
9
+
10
+ # Bind an argument to a method.
11
+ # Very useful for the proc shorthand.
12
+ # For example say there's a method "def add(a,b); print a + b; end"
13
+ # You can run it for each number in a list:
14
+ # [1,2,3].each &method(:add).bind(1)
15
+ # => 234
16
+ #
17
+ module Bind
18
+ def bind *args
19
+ Proc.new do |*more|
20
+ self.call *(args + more)
21
+ end
22
+ end
23
+ end
24
+
20
25
  end
21
26
 
22
27
  end
@@ -2,61 +2,81 @@
2
2
  #
3
3
  module Gemmy::Patches::ObjectPatch
4
4
 
5
- # Turns on verbose mode, showing warnings
6
- #
7
- def verbose_mode
8
- $VERBOSE = true
5
+ module ClassMethods
9
6
  end
10
7
 
11
- # Generic error. Raises RuntimeError
12
- # @param msg [String] optional
13
- #
14
- def error(msg='')
15
- raise RuntimeError, msg
16
- end
8
+ module InstanceMethods
17
9
 
18
- # Prints a string then gets input
19
- # @param txt [String]
20
- #
21
- def _prompt(txt)
22
- puts txt
23
- gets.chomp
24
- end
10
+ # Turns on verbose mode, showing warnings
11
+ #
12
+ module VerboseMode
13
+ def verbose_mode
14
+ $VERBOSE = true
15
+ end
16
+ end
25
17
 
26
- # Shifts one ARGV and raises a message if it's undefined.
27
- # @param msg [String]
28
- #
29
- def get_arg_or_error(msg)
30
- ([ARGV.shift, msg].tap &method(:error_if_blank)).shift
31
- end
18
+ # Generic error. Raises RuntimeError
19
+ # @param msg [String] optional
20
+ #
21
+ module Error
22
+ def error(msg='')
23
+ raise RuntimeError, msg
24
+ end
25
+ end
32
26
 
33
- # Writes a string to a file
34
- # @param file [String] path to write to
35
- # @param text [String] text to write
36
- #
37
- def write(file:, text:)
38
- File.open(file, 'w') { |f| f.write text }
39
- end
27
+ # Prints a string then gets input
28
+ # @param txt [String]
29
+ #
30
+ module Prompt
31
+ def _prompt(txt)
32
+ puts txt
33
+ gets.chomp
34
+ end
35
+ end
40
36
 
41
- # if args[0] (object) is blank, raises args[1] (message)
42
- # @param args [Array] - value 1 is obj, value 2 is msg
43
- #
44
- def error_if_blank(args)
45
- obj, msg = args
46
- obj.blank? && error(msg)
47
- end
37
+ # Shifts one ARGV and raises a message if it's undefined.
38
+ # @param msg [String]
39
+ #
40
+ module GetArgOrError
41
+ def get_arg_or_error(msg)
42
+ ([ARGV.shift, msg].tap &method(:error_if_blank)).shift
43
+ end
44
+ end
48
45
 
49
- # shorter proc shorthands
50
- #
51
- alias m method
46
+ # Writes a string to a file
47
+ # @param file [String] path to write to
48
+ # @param text [String] text to write
49
+ #
50
+ module Write
51
+ def write(file:, text:)
52
+ File.open(file, 'w') { |f| f.write text }
53
+ end
54
+ end
52
55
 
53
- # method which does absolutely nothing, ignoring all arguments
54
- #
55
- def nothing(*args)
56
- end
56
+ # if args[0] (object) is blank, raises args[1] (message)
57
+ # @param args [Array] - value 1 is obj, value 2 is msg
58
+ #
59
+ module ErrorIfBlank
60
+ def error_if_blank(args)
61
+ obj, msg = args
62
+ obj.blank? && error(msg)
63
+ end
64
+ end
65
+
66
+ module M
67
+ # shorter proc shorthands
68
+ def m(*args)
69
+ method(*args)
70
+ end
71
+ end
72
+
73
+ # method which does absolutely nothing, ignoring all arguments
74
+ #
75
+ module Nothing
76
+ def nothing(*args)
77
+ end
78
+ end
57
79
 
58
- refine Object do
59
- include Gemmy::Patches::ObjectPatch
60
80
  end
61
81
 
62
82
  end
@@ -2,20 +2,25 @@
2
2
  #
3
3
  module Gemmy::Patches::StringPatch
4
4
 
5
- # reference 'strip_heredoc' (provided by active support) by 'unindent'
6
- #
7
- # this takes an indented heredoc and treats it as if the first line is not
8
- # indented.
9
- #
10
- # Instead of using alias, a method is defined here to enable modular
11
- # patches
12
- #
13
- def unindent
14
- strip_heredoc
5
+ module ClassMethods
15
6
  end
16
7
 
17
- refine String do
18
- include Gemmy::Patches::StringPatch
8
+ module InstanceMethods
9
+
10
+ # reference 'strip_heredoc' (provided by active support) by 'unindent'
11
+ #
12
+ # this takes an indented heredoc and treats it as if the first line is not
13
+ # indented.
14
+ #
15
+ # Instead of using alias, a method is defined here to enable modular
16
+ # patches
17
+ #
18
+ module Unindent
19
+ def unindent
20
+ strip_heredoc
21
+ end
22
+ end
23
+
19
24
  end
20
25
 
21
26
  end
@@ -2,18 +2,24 @@
2
2
  #
3
3
  module Gemmy::Patches::SymbolPatch
4
4
 
5
- # Patch symbol so the proc shorthand can take extra arguments
6
- # http://stackoverflow.com/a/23711606/2981429
7
- #
8
- # Example: [1,2,3].map &:*.with(2)
9
- # => [2,4,6]
10
- #
11
- def with(*args, &block)
12
- ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
5
+ module ClassMethods
13
6
  end
14
7
 
15
- refine Symbol do
16
- include Gemmy::Patches::SymbolPatch
8
+ module InstanceMethods
9
+
10
+ # Patch symbol so the proc shorthand can take extra arguments
11
+ # http://stackoverflow.com/a/23711606/2981429
12
+ #
13
+ # Example: [1,2,3].map &:*.with(2)
14
+ # => [2,4,6]
15
+ #
16
+ module With
17
+ def with(*args, &block)
18
+ ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
19
+ end
20
+ end
21
+
17
22
  end
18
23
 
24
+
19
25
  end
@@ -5,14 +5,17 @@
5
5
  #
6
6
  module Gemmy::Patches::ThreadPatch
7
7
 
8
- # Ensure that threads bubble up their errors
9
- #
10
- def self.included(base)
11
- Thread.abort_on_exception = true
8
+ module ClassMethods
9
+ module Included
10
+ # Ensure that threads bubble up their errors
11
+ #
12
+ def self.included(base)
13
+ Thread.abort_on_exception = true
14
+ end
15
+ end
12
16
  end
13
17
 
14
- refine Thread do
15
- include Gemmy::Patches::ThreadPatch
18
+ module InstanceMethods
16
19
  end
17
20
 
18
21
  end
data/lib/gemmy/patches.rb CHANGED
@@ -1,23 +1,89 @@
1
1
  # Gemmy provides patches for a few of the core classes.
2
2
  #
3
- # See {Gemmy#load_globally} for how to load these on the root namespace
3
+ # Use Gemmy#load_globally to load these on the root namespace
4
4
  # For a refinements-based approach, use this in a class/module definition:
5
5
  #
6
- # Gemmy::Patches.refinements.each { |klass| using klass }
6
+ # Gemmy::Patches.class_refinements.each { |klass| using klass }
7
7
  #
8
- # Note that there are nuances for how refinements are used. You can't refer to
9
- # the patches using define_method, for example.
8
+ # Note that there are nuances for how refinements are used.
9
+ # You can't refer to the patches using define_method, for example.
10
10
  #
11
11
  # See examples/01_using_as_refinement.rb for more info
12
+ # (linked from the README at github.com/maxpleaner/gemmy
12
13
  #
13
14
  module Gemmy::Patches
14
15
 
15
- def self.refinements(only: nil, except: nil)
16
- core_patches.select do |core_klass, patch_klass|
17
- return false if only && !only.include?(core_klass)
18
- return false if except && except.include?(core_klass)
19
- true
20
- end.values
16
+ # The usage of this method is to load all the patches for some core classes.
17
+ # With no arguments it will include all patches
18
+ # There are two optional params (keyword arguments).
19
+ # @param only [Array<Symbol>] if provided, will only patch those classes
20
+ # @param except [Array<Symbol>] if provided, will exclude those classes
21
+ # @return [Array<Class>] to be iteratively passed to 'using'
22
+ def self.class_refinements(only: nil, except: nil)
23
+ return @@refined if defined? @@refined
24
+ @@refined = core_patches.reduce([]) do |arr, (core_klass_sym, patch_klass)|
25
+ next if only && !only.include?(core_klass_sym)
26
+ next if except && except.include?(core_klass_sym)
27
+ core_klass = const_get core_klass_sym.to_s
28
+ class_patches = patch_klass.const_get "ClassMethods"
29
+ instance_patches = patch_klass.const_get "InstanceMethods"
30
+ class_patches.constants.each do |patch_class_sym|
31
+ patch_class = class_patches.const_get patch_class_sym
32
+ patch_as_class_method(core_klass, patch_class)
33
+ arr.push patch_class
34
+ end
35
+ instance_patches.constants.each do |patch_class_sym|
36
+ patch_class = instance_patches.const_get patch_class_sym
37
+ patch_as_instance_method(core_klass, patch_class)
38
+ arr.push patch_class
39
+ end
40
+ arr
41
+ end.compact
42
+ @@refined
43
+ end
44
+
45
+ # Cherry pick methods to patch.
46
+ # @param hash [Hash] with a particular structure:
47
+ # top level keys are Symbols referring to core classes, i.e. :String
48
+ # top level values are hashes.
49
+ # second level keys are either :ClassMethods or :InstanceMethods
50
+ # referring to the scope
51
+ # second level values are arrays of symbols (one per method)
52
+ #
53
+ # To give an example:
54
+ #
55
+ # Gemmy::Patches.method_refinements(
56
+ # Array: { InstanceMethods: [:Recurse, :KeyBy] }
57
+ # ).each { |r| using r }
58
+ #
59
+ def self.method_refinements(hash)
60
+ hash.map do |core_klass_sym, patch_types|
61
+ core_class = const_get(core_klass_sym)
62
+ patch_types.map do |type_sym, patch_method_syms|
63
+ patch_methods = core_patches[core_klass_sym].const_get type_sym.to_s
64
+ patch_method_syms.map do |patch_method_sym|
65
+ method_class = patch_methods.const_get(patch_method_sym)
66
+ if type_sym == :InstanceMethods
67
+ patch_as_instance_method(core_class, method_class)
68
+ elsif type_sym == :ClassMethods
69
+ patch_as_class_method(core_class, method_class)
70
+ end
71
+ method_class
72
+ end
73
+ end
74
+ end.flatten.compact
75
+ end
76
+
77
+ def self.patch_as_class_method(core_klass, patch_klass)
78
+ patch_klass.send(:refine, core_klass.singleton_class) do
79
+ include patch_klass
80
+ end
81
+ end
82
+
83
+ def self.patch_as_instance_method(core_klass, patch_klass)
84
+ patch_klass.send(:refine, core_klass) do
85
+ include patch_klass
86
+ end
21
87
  end
22
88
 
23
89
  def self.core_patches
@@ -25,10 +91,11 @@ module Gemmy::Patches
25
91
  String: Gemmy::Patches::StringPatch,
26
92
  Symbol: Gemmy::Patches::SymbolPatch,
27
93
  Object: Gemmy::Patches::ObjectPatch,
28
- Array: Gemmy::Patches::ArrayPatch,
94
+ Array: Gemmy::Patches::ArrayPatch,
29
95
  Method: Gemmy::Patches::MethodPatch,
30
- Hash: Gemmy::Patches::HashPatch,
96
+ Hash: Gemmy::Patches::HashPatch,
31
97
  Thread: Gemmy::Patches::ThreadPatch,
98
+ Integer: Gemmy::Patches::IntegerPatch
32
99
  }.with_indifferent_access
33
100
  end
34
101
 
@@ -21,7 +21,7 @@
21
21
  #
22
22
  class Gemmy::Tasks::MakeGem
23
23
 
24
- Gemmy::Patches.refinements.each { |r| using r }
24
+ Gemmy::Patches.class_refinements.each { |r| using r }
25
25
 
26
26
  # Builds a skeleton ruby gem.
27
27
  # Prompts for some input using gets.chomp
@@ -1,6 +1,6 @@
1
1
  module Gemmy::Tests::ComponentTests::DynamicStepsTests
2
2
 
3
- Gemmy::Patches.refinements.each { |r| using r }
3
+ Gemmy::Patches.class_refinements.each { |r| using r }
4
4
 
5
5
  def self.run
6
6
  runner_class = Class.new
@@ -18,4 +18,5 @@ module Gemmy::Tests::ComponentTests::DynamicStepsTests
18
18
  puts " step".blue
19
19
  end
20
20
  end
21
+
21
22
  end
@@ -26,7 +26,7 @@ module Gemmy::Tests
26
26
 
27
27
  class PatchedClass
28
28
 
29
- Gemmy::Patches.refinements.each { |r| using r }
29
+ Gemmy::Patches.class_refinements.each { |r| using r }
30
30
 
31
31
  extend Gemmy::Tests::PatchTests::Error
32
32
 
data/lib/gemmy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Gemmy
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  end
data/lib/gemmy.rb CHANGED
@@ -15,13 +15,28 @@ class Gemmy
15
15
  # This is the method handling the global case
16
16
  #
17
17
  def self.load_globally
18
- Patches.core_patches.each do |core_klass_name, patch_klass|
19
- core_klass_name.to_s.constantize.include patch_klass
18
+ core_patches = Patches.core_patches.map do |core_klass_name, patch_klass|
19
+ core_klass = core_klass_name.to_s.constantize
20
+ instance_method_class = patch_klass.const_get("InstanceMethods")
21
+ class_method_class = patch_klass.const_get("ClassMethods")
22
+ instance_classes = instance_method_class.constants.map do |klass_sym|
23
+ klass = instance_method_class.const_get klass_sym
24
+ core_klass.include klass
25
+ klass
26
+ end
27
+ class_classes = class_method_class.constants.map do |klass_sym|
28
+ klass = class_method_class.const_get klass_sym
29
+ core_klass.extend klass
30
+ klass
31
+ end
32
+ [instance_classes, class_classes]
20
33
  end
21
- Components.list.each do |patch_klass|
34
+ components = Components.list.map do |patch_klass|
22
35
  Object.include patch_klass
23
36
  Object.extend patch_klass
37
+ patch_klass
24
38
  end
39
+ [components, core_patches].flatten
25
40
  end
26
41
  end
27
42
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gemmyrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - max pleaner
@@ -102,6 +102,7 @@ files:
102
102
  - lib/gemmy/patches.rb
103
103
  - lib/gemmy/patches/array_patch.rb
104
104
  - lib/gemmy/patches/hash_patch.rb
105
+ - lib/gemmy/patches/integer_patch.rb
105
106
  - lib/gemmy/patches/method_patch.rb
106
107
  - lib/gemmy/patches/object_patch.rb
107
108
  - lib/gemmy/patches/string_patch.rb