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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7209ee253dbd083df7df4be1c0596cf3be0b45eb
4
- data.tar.gz: 9cb680779c32389e770bceb047b4440c5e39c423
3
+ metadata.gz: d30ca22dee6e6cde7f9f34d17995ff7b27f6b37c
4
+ data.tar.gz: a0b476f59450a277e1ad55f2927240a5689e978a
5
5
  SHA512:
6
- metadata.gz: 37ce51cdf63d82c08b78305427e23b1c6721533e5486bc7416ab9d9f3cf774b5fabf74af09c35b3385f0371a4c5c818c35e07b7f3c180e7c825d4411f93f3846
7
- data.tar.gz: 654e3a115be6951f928a4e56441668eaad7b3f49f224dd3ee5f463a4eb2b5fbfb1c8098c5bb48daeb783c8a5e18132caa16b53b645a6467c872d63a635b5b08e
6
+ metadata.gz: f3a3077967091d00545cce2ccdbff1a76360f51150939374c2e5b402191b0beee12133af44ee5f8debb00390878225b4ac031c7ba964cec776173ae978fb998f
7
+ data.tar.gz: 058f353934143317f307ea99626480ff2f50558880ae25fb4eea2d69ccaaf77a1bf706b02af365cd5078dc714ded18ad0af7b31fd566b4551d806c990fca1a3e
@@ -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/**/*'
@@ -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
@@ -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! case hos
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 :#{ASPECT_PREFIX}#{meth}, :#{meth}
148
+ alias_method :'#{ASPECT_PREFIX}#{meth}', :'#{meth}'
130
149
  def #{meth}(*args, &cb)
131
- ps = self.class.aspects(:#{meth}).merge((class << self; self; end).aspects(:#{meth})) { |_, c, ec| c | ec }
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) # TODO: make prependers able to change args!!!
152
+ p.call(self, :'#{meth}', nil, *args) # FIXME: allow argument modification!!!
134
153
  end
135
- send(:#{ASPECT_PREFIX}#{meth}, *args, &cb).tap do |result|
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
@@ -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
- raise ArgumentError, "Trying to attach nothing to #{klazz}. I need a block!" unless block_given?
22
-
23
- klazz = to.is_a?(Class) ? to : class << to; self; end # attach to klazz’s eigenclass if object given
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
@@ -1,3 +1,3 @@
1
1
  module Kungfuig
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.0"
3
3
  end
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.2
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-23 00:00:00.000000000 Z
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: