kungfuig 0.4.2 → 0.5.0
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 +4 -4
- data/.rubocop.yml +10 -0
- data/kungfuig.gemspec +3 -0
- data/lib/kungfuig.rb +48 -29
- data/lib/kungfuig/aspector.rb +48 -6
- data/lib/kungfuig/jobber.rb +41 -0
- data/lib/kungfuig/version.rb +1 -1
- metadata +37 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d30ca22dee6e6cde7f9f34d17995ff7b27f6b37c
|
4
|
+
data.tar.gz: a0b476f59450a277e1ad55f2927240a5689e978a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3a3077967091d00545cce2ccdbff1a76360f51150939374c2e5b402191b0beee12133af44ee5f8debb00390878225b4ac031c7ba964cec776173ae978fb998f
|
7
|
+
data.tar.gz: 058f353934143317f307ea99626480ff2f50558880ae25fb4eea2d69ccaaf77a1bf706b02af365cd5078dc714ded18ad0af7b31fd566b4551d806c990fca1a3e
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
inherit_from: .rubocop_todo.yml
|
2
2
|
|
3
|
+
Style/AsciiIdentifiers:
|
4
|
+
Exclude:
|
5
|
+
- 'lib/**/*'
|
6
|
+
- 'spec/**/*'
|
7
|
+
|
3
8
|
Style/AsciiComments:
|
4
9
|
Exclude:
|
5
10
|
- 'lib/**/*'
|
@@ -8,3 +13,8 @@ Style/AsciiComments:
|
|
8
13
|
Style/RaiseArgs:
|
9
14
|
Exclude:
|
10
15
|
- 'lib/**/*'
|
16
|
+
|
17
|
+
Style/SpecialGlobalVars:
|
18
|
+
Exclude:
|
19
|
+
- 'lib/**/*'
|
20
|
+
- 'spec/**/*'
|
data/kungfuig.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
# spec.metadata['allowed_push_host'] = 'http://mygemserver.com' if spec.respond_to?(:metadata)
|
23
23
|
|
24
24
|
spec.add_dependency 'hashie', '~> 3'
|
25
|
+
spec.add_dependency 'sidekiq', '~> 3.5', '>= 3.5.2'
|
25
26
|
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
27
28
|
spec.add_development_dependency 'rake', '~> 10.0'
|
@@ -30,4 +31,6 @@ Gem::Specification.new do |spec|
|
|
30
31
|
spec.add_development_dependency 'rspec', '~> 2.12'
|
31
32
|
spec.add_development_dependency 'cucumber', '~> 1.3'
|
32
33
|
spec.add_development_dependency 'yard', '~> 0'
|
34
|
+
|
35
|
+
spec.add_development_dependency 'rspec-sidekiq', '~> 1'
|
33
36
|
end
|
data/lib/kungfuig.rb
CHANGED
@@ -1,11 +1,52 @@
|
|
1
|
-
require 'kungfuig/version'
|
2
1
|
require 'yaml'
|
3
2
|
require 'hashie'
|
4
3
|
|
4
|
+
require 'kungfuig/version'
|
5
|
+
require 'kungfuig/aspector'
|
6
|
+
|
5
7
|
module Kungfuig
|
6
8
|
ASPECT_PREFIX = '♻_'.freeze
|
7
9
|
MX = Mutex.new
|
8
10
|
|
11
|
+
# rubocop:disable Style/VariableName
|
12
|
+
# rubocop:disable Style/MethodName
|
13
|
+
def ✍(receiver, method, result, *args)
|
14
|
+
require 'logger'
|
15
|
+
@✍ ||= Kernel.const_defined?('Rails') && Rails.logger || Logger.new($stdout)
|
16
|
+
message = receiver.is_a?(String) ? "#{receiver} | #{method}" : "#{receiver.class}##{method}"
|
17
|
+
"#{message} called with «#{args.inspect}» and returned «#{result || 'nothing (was it before aspect?)'}»".tap do |m|
|
18
|
+
@✍.debug m
|
19
|
+
end
|
20
|
+
end
|
21
|
+
module_function :✍
|
22
|
+
# rubocop:enable Style/MethodName
|
23
|
+
# rubocop:enable Style/VariableName
|
24
|
+
|
25
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
26
|
+
# rubocop:disable Metrics/MethodLength
|
27
|
+
def load_stuff hos
|
28
|
+
case hos
|
29
|
+
when NilClass then Hashie::Mash.new # aka skip
|
30
|
+
when Hash then Hashie::Mash.new(hos)
|
31
|
+
when String
|
32
|
+
begin
|
33
|
+
File.exist?(hos) ? Hashie::Mash.load(hos) : Hashie::Mash.new(YAML.load(hos)).tap do |opts|
|
34
|
+
fail ArgumentError.new "#{__callee__} expects valid YAML configuration file or YAML string." unless opts.is_a?(Hash)
|
35
|
+
end
|
36
|
+
rescue ArgumentError
|
37
|
+
fail ArgumentError.new "#{__callee__} expects valid YAML configuration file. [#{hos}] contains invalid syntax."
|
38
|
+
rescue Psych::SyntaxError
|
39
|
+
fail ArgumentError.new "#{__callee__} expects valid YAML configuration string. Got:\n#{hos}"
|
40
|
+
end
|
41
|
+
when ->(h) { h.respond_to?(:to_hash) } then Hashie::Mash.new(h.to_hash)
|
42
|
+
else
|
43
|
+
fail ArgumentError.new "#{__callee__} accepts either String or Hash as parameter."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
# rubocop:enable Metrics/MethodLength
|
47
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
48
|
+
module_function :load_stuff
|
49
|
+
|
9
50
|
module InstanceMethods
|
10
51
|
# Configures everything by hash or yaml from string or file. Whether code block
|
11
52
|
# is passed, it is processed with @options instance.
|
@@ -64,34 +105,12 @@ module Kungfuig
|
|
64
105
|
!option(*keys).nil?
|
65
106
|
end
|
66
107
|
|
67
|
-
# rubocop:disable Metrics/AbcSize
|
68
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
69
|
-
# rubocop:disable Metrics/MethodLength
|
70
108
|
# @param hos [Hash|String] the new values taken from hash,
|
71
109
|
# mash or string (when string, should be either valid YAML file name or
|
72
110
|
# string with valid YAML)
|
73
111
|
def merge_hash_or_string! hos
|
74
|
-
options.deep_merge!
|
75
|
-
when NilClass then Hashie::Mash.new # aka skip
|
76
|
-
when Hash then Hashie::Mash.new(hos)
|
77
|
-
when String
|
78
|
-
begin
|
79
|
-
File.exist?(hos) ? Hashie::Mash.load(hos) : Hashie::Mash.new(YAML.load(hos)).tap do |opts|
|
80
|
-
fail ArgumentError.new "#{__callee__} expects valid YAML configuration file or YAML string." unless opts.is_a?(Hash)
|
81
|
-
end
|
82
|
-
rescue ArgumentError
|
83
|
-
fail ArgumentError.new "#{__callee__} expects valid YAML configuration file. [#{hos}] contains invalid syntax."
|
84
|
-
rescue Psych::SyntaxError
|
85
|
-
fail ArgumentError.new "#{__callee__} expects valid YAML configuration string. Got:\n#{hos}"
|
86
|
-
end
|
87
|
-
when ->(h) { h.respond_to?(:to_hash) } then Hashie::Mash.new(h.to_hash)
|
88
|
-
else
|
89
|
-
fail ArgumentError.new "#{__callee__} accepts either String or Hash as parameter."
|
90
|
-
end
|
112
|
+
options.deep_merge! Kungfuig.load_stuff hos
|
91
113
|
end
|
92
|
-
# rubocop:enable Metrics/MethodLength
|
93
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
94
|
-
# rubocop:enable Metrics/AbcSize
|
95
114
|
private :merge_hash_or_string!
|
96
115
|
end
|
97
116
|
|
@@ -126,15 +145,15 @@ module Kungfuig
|
|
126
145
|
|
127
146
|
unless instance_methods.include?(:"#{ASPECT_PREFIX}#{meth}")
|
128
147
|
class_eval <<-CODE
|
129
|
-
alias_method
|
148
|
+
alias_method :'#{ASPECT_PREFIX}#{meth}', :'#{meth}'
|
130
149
|
def #{meth}(*args, &cb)
|
131
|
-
ps = self.class.aspects(
|
150
|
+
ps = self.class.aspects(:'#{meth}').merge((class << self; self; end).aspects(:'#{meth}')) { |_, c, ec| c | ec }
|
132
151
|
ps[:before].each do |p|
|
133
|
-
p.call(*args) #
|
152
|
+
p.call(self, :'#{meth}', nil, *args) # FIXME: allow argument modification!!!
|
134
153
|
end
|
135
|
-
send(
|
154
|
+
send(:'#{ASPECT_PREFIX}#{meth}', *args, &cb).tap do |result|
|
136
155
|
ps[:after].each do |p|
|
137
|
-
p.call result, *args
|
156
|
+
p.call(self, :'#{meth}', result, *args)
|
138
157
|
end
|
139
158
|
end
|
140
159
|
end
|
data/lib/kungfuig/aspector.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require_relative '../kungfuig'
|
2
|
-
|
3
1
|
module Kungfuig
|
4
2
|
# Generic helper for massive attaching aspects
|
5
3
|
module Aspector
|
@@ -10,26 +8,45 @@ module Kungfuig
|
|
10
8
|
v = [*v].map(&:to_sym)
|
11
9
|
case
|
12
10
|
when v.empty? then []
|
13
|
-
when v.include?(:'*') then klazz.instance_methods(false)
|
11
|
+
when v.include?('*'), v.include?(:'*') then klazz.instance_methods(false)
|
14
12
|
else klazz.instance_methods & v
|
15
13
|
end
|
16
14
|
end.reduce(&:-)
|
17
15
|
end
|
16
|
+
|
17
|
+
def remap_hash_for_easy_iteration hash
|
18
|
+
hash = hash.each_with_object(Hashie::Mash.new) do |(k, v), memo|
|
19
|
+
v.each { |m, c| memo.public_send("#{m}!")[k] = c }
|
20
|
+
end unless (hash.keys - %w(before after exclude)).empty?
|
21
|
+
hash.each_with_object({}) do |(k, v), memo|
|
22
|
+
v.each { |m, h| ((memo[h] ||= {})[k.to_sym] ||= []) << m }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def proc_instance string
|
27
|
+
m, k = string.split('#').reverse
|
28
|
+
(k ? Kernel.const_get(k).method(m) : method(m)).to_proc
|
29
|
+
end
|
18
30
|
end
|
19
31
|
|
20
32
|
def attach(to, before: nil, after: nil, exclude: nil)
|
21
|
-
|
22
|
-
|
23
|
-
|
33
|
+
klazz = case to
|
34
|
+
when String then Kernel.const_get(to) # we are ready to get a class name
|
35
|
+
when Class then to # got a class! wow, somebody has the documentation read
|
36
|
+
else class << to; self; end # attach to klazz’s eigenclass if object given
|
37
|
+
end
|
24
38
|
|
39
|
+
raise ArgumentError, "Trying to attach nothing to #{klazz}##{to}. I need a block!" unless block_given?
|
25
40
|
klazz.send(:include, Kungfuig::Aspector) unless klazz.ancestors.include? Kungfuig::Aspector
|
26
41
|
cb = Proc.new
|
27
42
|
|
28
43
|
H.new.value_to_method_list(klazz, before, exclude).each do |m|
|
44
|
+
# FIXME: log methods that failed to be wrapped more accurately? # Kungfuig.✍(klazz, m, e.inspect)
|
29
45
|
klazz.aspect(m, false, &cb)
|
30
46
|
end unless before.nil?
|
31
47
|
|
32
48
|
H.new.value_to_method_list(klazz, after, exclude).each do |m|
|
49
|
+
# FIXME: log methods that failed to be wrapped more accurately? # Kungfuig.✍(klazz, m, e.inspect)
|
33
50
|
klazz.aspect(m, true, &cb)
|
34
51
|
end unless after.nil?
|
35
52
|
|
@@ -37,6 +54,31 @@ module Kungfuig
|
|
37
54
|
end
|
38
55
|
module_function :attach
|
39
56
|
|
57
|
+
# 'Test':
|
58
|
+
# after:
|
59
|
+
# 'yo': 'YoCalledAsyncHandler#process'
|
60
|
+
# 'yo1' : 'YoCalledAsyncHandler#process'
|
61
|
+
# before:
|
62
|
+
# 'yo': 'YoCalledAsyncHandler#process'
|
63
|
+
def bulk(hos)
|
64
|
+
Kungfuig.load_stuff(hos).map do |klazz, hash|
|
65
|
+
next if hash.empty?
|
66
|
+
[klazz, H.new.remap_hash_for_easy_iteration(hash).map do |handler, methods|
|
67
|
+
begin
|
68
|
+
attach(klazz, **methods, &H.new.proc_instance(handler))
|
69
|
+
rescue => e
|
70
|
+
raise ArgumentError, [
|
71
|
+
"Bad input to Kungfuig::Aspector##{__callee__}.",
|
72
|
+
"Args: #{methods.inspect}",
|
73
|
+
"Original exception: “#{e.message}”.",
|
74
|
+
e.backtrace.unshift("Backtrace:").join("#{$/}⮩ ")
|
75
|
+
].join($/.to_s)
|
76
|
+
end
|
77
|
+
end]
|
78
|
+
end.compact.to_h
|
79
|
+
end
|
80
|
+
module_function :bulk
|
81
|
+
|
40
82
|
private_constant :H
|
41
83
|
end
|
42
84
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative './aspector'
|
2
|
+
require 'rubygems/exceptions'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'sidekiq'
|
6
|
+
raise LoadError.new unless Kernel.const_defined?('Sidekiq')
|
7
|
+
rescue LoadError
|
8
|
+
raise(Gem::DependencyError, "Sidekiq id required to use this functionality!")
|
9
|
+
end
|
10
|
+
|
11
|
+
module Kungfuig
|
12
|
+
# Generic helper for massive attaching aspects
|
13
|
+
class Jobber
|
14
|
+
class << self
|
15
|
+
# 'Test':
|
16
|
+
# '*': 'YoJob'
|
17
|
+
def bulk(hos)
|
18
|
+
@hash = Kungfuig.load_stuff hos
|
19
|
+
Kungfuig::Aspector.bulk(
|
20
|
+
@hash.map do |klazz, hash|
|
21
|
+
[klazz, { after: hash.map { |k, _| [k, 'Kungfuig::Jobber#bottleneck'] }.to_h }]
|
22
|
+
end.to_h
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def bottleneck(receiver, method, result, *args)
|
27
|
+
respond_to = ->(m, r) { r.respond_to? m.to_sym }
|
28
|
+
r = case receiver
|
29
|
+
when respond_to.curry[:to_hash] then receiver.to_hash
|
30
|
+
when respond_to.curry[:to_h] then receiver.to_h
|
31
|
+
else receiver
|
32
|
+
end
|
33
|
+
|
34
|
+
Kernel.const_get(@hash[receiver.class.name][method])
|
35
|
+
.perform_async(r, method, result, *args)
|
36
|
+
rescue => e
|
37
|
+
Kungfuig.✍("Fail [#{e.message}] while #{receiver}", method, result, *args)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/kungfuig/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kungfuig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kantox LTD
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashie
|
@@ -24,6 +24,26 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sidekiq
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.5'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 3.5.2
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '3.5'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.5.2
|
27
47
|
- !ruby/object:Gem::Dependency
|
28
48
|
name: bundler
|
29
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +128,20 @@ dependencies:
|
|
108
128
|
- - "~>"
|
109
129
|
- !ruby/object:Gem::Version
|
110
130
|
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: rspec-sidekiq
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '1'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '1'
|
111
145
|
description: Config with goodnesses.
|
112
146
|
email:
|
113
147
|
- aleksei.matiushkin@kantox.com
|
@@ -126,6 +160,7 @@ files:
|
|
126
160
|
- kungfuig.gemspec
|
127
161
|
- lib/kungfuig.rb
|
128
162
|
- lib/kungfuig/aspector.rb
|
163
|
+
- lib/kungfuig/jobber.rb
|
129
164
|
- lib/kungfuig/version.rb
|
130
165
|
homepage: http://kantox.com
|
131
166
|
licenses:
|