eitil 0.3.3 → 0.3.8

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: 7472becb49f3ad8ed37b1af23436257255cd050fd6d101a552fad3b35d020e38
4
- data.tar.gz: 3508a76cd84733740cc9b8e9be223406ec4f620f38d9ba86048118743c058dd5
3
+ metadata.gz: f742ee647b11b18765c5022fe55301317822282c3443cd161e0d49ded69678cf
4
+ data.tar.gz: 10aa2196982292c2cab87a25906b59eba9147294dfdddaafce8a53eb8521c7b7
5
5
  SHA512:
6
- metadata.gz: 52c7c51884686864b8b1aede6fc70a03028636614ef309ef59f9a70336091bd1e122ca2e7ccd99dcd824e371c60a83db73924cda249c373fda62b6f548af32fd
7
- data.tar.gz: 47071fee4cd78efdda04753406985bb093150b70e4d1bcfd355091f3c402cd08603a508c234e3dec2d9d324c1e2a23f0f86c2ae33d1bd914b0c5f1d3631d0de6
6
+ metadata.gz: 13b655a01ff36fd371f50cc9868409a0a0d51520afffaf3d8871bd9955a502bf342945f51d0f551cbd9c58b97bdcc6fa7d28f9a09ee06b9c1e127764abbc3854
7
+ data.tar.gz: c7a02991659f2c23d9c4846d2377e6160a3f15fdd0119f231ad1e78fef0686ba651c35c25b283f49405cd5f1fc545d40d082c7ff7639ee080cef76d8b25ff7b6
data/README.md CHANGED
@@ -103,6 +103,20 @@ include_concerns_of(*directories, namespace: nil)
103
103
 
104
104
 
105
105
 
106
+ ## String
107
+
108
+ ```ruby
109
+ is_num?
110
+ # returns true if a string matches the Rubinius source code regex for strings and integers, false otherwise
111
+ # comes in handy since ruby plays it safe on string to number conversion ('aaa'.to_f returns 0.0, thus is valid)
112
+
113
+ is_nan?
114
+ # returns true if a string does NOT match the Rubinius source code regex for strings and integers, false otherwise
115
+ # comes in handy since ruby plays it safe on string to number conversion ('aaa'.to_f returns 0.0, thus is valid)
116
+ ```
117
+
118
+
119
+
106
120
  ## Hash
107
121
 
108
122
  ```ruby
@@ -131,6 +145,14 @@ slice_params(*args)
131
145
  self.all_associations
132
146
  # returns all associations for a given model
133
147
  # call as: Environment.all_associations
148
+
149
+ self.where_like(_hash)
150
+ # runs .where with your string field made into a wildcard and case insensitive
151
+ # call as: User.where_like(name: 'jurriaan')
152
+
153
+ self.find_by_like(_hash)
154
+ # runs .find_by with your string field made into a wildcard and case insensitive
155
+ # call as: User.find_by_like(name: 'jurriaan')
134
156
  ```
135
157
 
136
158
 
@@ -177,7 +199,7 @@ decorate(dec_item, dec_method: nil, dec_class: nil, **dec_kwargs)
177
199
  # initializers/eitil.rb
178
200
 
179
201
  Eitil.set_config do |config|
180
- config.get_controller_ivars_method = 'API::VerlofVerzoekenController.controller_ivars' # => [:user, :env]
202
+ config.get_controller_ivars_method = 'API::BaseController.controller_ivars' # => [:user, :env]
181
203
  end
182
204
  ```
183
205
 
@@ -227,14 +249,18 @@ The router wrapper is a single module which is automatically included into your
227
249
 
228
250
  ### Info
229
251
 
230
- The Eitil jobs wrapper enables you to create perform_later jobs on the fly, without the need to create a new class and file. The macro new_job accepts a :method as argument and defines a new method :method_job. The newly defined :method_job, when called, performs the orginal :method in the background. The new_job macro accepts both instance methods and singleton methods, which are defined within there own method scope.
252
+ The Eitil jobs wrapper enables you to create perform_now and perform_later jobs on the fly, without the need to create a new class and file. The macro new_job accepts a :method as argument and defines a new method :method_job. The newly defined :method_job, when called, performs the orginal :method in the background. The new_job macro accepts both instance methods and singleton methods, which are defined within there own method scope. In contrast, the new_job_debugger macro defines a new :method_job_debugger method, which performs in the foreground.
231
253
 
232
254
  ### Job Macro
233
255
 
234
256
  ```ruby
235
- new_job(_method)
236
- # assuming a method :print_hello_world, call as: new_job :hello_world
237
- # => method :hello_world_job
257
+ new_job(_method, *args, **kwargs)
258
+ # assuming a method :hello_world, call as: new_job :hello_world
259
+ # => defines :hello_world_job
260
+
261
+ new_job_debugger(_method, *args, **kwargs)
262
+ # assuming a method :hello_world, call as: new_job_debugger :hello_world
263
+ # => defines :hello_world_job_debugger
238
264
  ```
239
265
 
240
266
  - method is
@@ -304,3 +330,50 @@ Scopes are generated through the columns of your model's database table. Which s
304
330
  Your models should inherit the module Eitil::DefaultScopes through inclusion in a superclass, such as ApplicationRecord.
305
331
 
306
332
 
333
+
334
+ # Modules & Classes
335
+
336
+
337
+
338
+ ## Eitil::Dir
339
+
340
+ ### Info
341
+
342
+ The Eitil::Dir module provides methods which help you introspect your Rails project.
343
+
344
+ ### Methods
345
+
346
+ ```ruby
347
+ Eitil::Dir.contents(directory='app')
348
+ # returns all files and subdirectories of a given directory
349
+
350
+ Eitil::Dir.files(directory='app')
351
+ # returns all files of a given directory
352
+
353
+ Eitil::Dir.subdirs(directory='app')
354
+ # returns all subdirectories of a given directory
355
+
356
+ Eitil::Dir.lines(directory='app')
357
+ # returns the total amount of lines of all files of a given directory
358
+ ```
359
+
360
+
361
+
362
+ ## Eitil::StackTrace
363
+
364
+ ### Info
365
+
366
+ The two classes Eitil::StackTrace::Stack and Eitil::StackTrace::Call, and the single module Eitil::StackTrace::Audit, provide the utility of easily viewing and storing the current stacktrace anywhere in your code. By initializing stack = Eitil::StackTrace::Stack.new, you can call methods as stack.report (returns the stacktrace as array), stack.show (pretty prints the stacktrace) and stack.find (accepts a block to find a call).
367
+
368
+ You can also store the stacktrace of a record's update action into its audit. In order to do so, you need 1) to include Eitil::StackTrace::Audit into your model, and 2) add a :stacktrace column to your audits through the following migration.
369
+
370
+ ### Migration
371
+
372
+ ```ruby
373
+ def change
374
+ add_column :audits, :stacktrace, :text, array: true, default: []
375
+ end
376
+ ```
377
+
378
+
379
+
@@ -0,0 +1,15 @@
1
+ module Eitil::StackTrace::Audit
2
+ extend ActiveSupport::Concern
3
+ included do
4
+
5
+ private
6
+
7
+ after_update :add_stacktrace_to_audit
8
+
9
+ def add_stacktrace_to_audit
10
+ stacktrace = Eitil::StackTrace::Stack.new.report
11
+ self.audits.last.update(stacktrace: stacktrace)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module Eitil::StackTrace
2
+ class Call
3
+
4
+ attr_reader :program, :line, :meth
5
+
6
+ CALL_RE = /(.*):(\d+):in `(.*)'/
7
+
8
+ def initialize(string)
9
+ @program, @line, @meth = CALL_RE.match(string).captures
10
+ end
11
+
12
+ def to_s
13
+ "#{"#{meth}".ljust(50)} #{"(#{line})".ljust(6)} #{program}"
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ module Eitil::StackTrace
2
+ class Stack
3
+
4
+ attr_reader :stack, :backtrace
5
+
6
+ def initialize
7
+ @stack = caller[1..]
8
+ @backtrace = stack.map { |call| Eitil::StackTrace::Call.new(call) }
9
+ end
10
+
11
+ def report
12
+ backtrace.map(&:to_s)
13
+ end
14
+
15
+ def show
16
+ ap report
17
+ end
18
+
19
+ def find(&block)
20
+ backtrace.find(&block)
21
+ end
22
+
23
+ def self.parse(array_as_string)
24
+ array_as_string.sub('[', ' ').reverse.sub(']','').reverse.split(',').flatten
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ module Eitil::Dir
2
+ class << self
3
+
4
+ def contents(directory='app')
5
+ Dir[File.join(directory, '**', '*')]
6
+ end
7
+
8
+ def files(directory='app')
9
+ contents(directory).select { |file| File.file?(file) }
10
+ end
11
+
12
+ def subdirs(directory='app')
13
+ contents(directory).select { |file| File.directory?(file) }
14
+ end
15
+
16
+ def lines(directory='app')
17
+ files(directory).map { |file| File.open(file).count }.sum
18
+ end
19
+
20
+ end
21
+ end
@@ -4,10 +4,24 @@ module ApplicationRecordMonkey
4
4
  extend ActiveSupport::Concern
5
5
  included do
6
6
 
7
- def self.all_associations
8
- reflect_on_all_associations.map do |assoc|
9
- { assoc.name => assoc.association_class.to_s.demodulize }
10
- end.inject &:merge
7
+ class << self
8
+
9
+ def all_associations
10
+ reflect_on_all_associations.map do |assoc|
11
+ { assoc.name => assoc.association_class.to_s.demodulize }
12
+ end.inject &:merge
13
+ end
14
+
15
+ def where_like(_hash)
16
+ column, like = _hash.first
17
+ where("LOWER(#{column}) LIKE ?", "%#{like.downcase}%")
18
+ end
19
+
20
+ def find_by_like(_hash)
21
+ column, like = _hash.first
22
+ find_by("LOWER(#{column}) LIKE ?", "%#{like.downcase}%")
23
+ end
24
+
11
25
  end
12
26
 
13
27
  end
@@ -8,7 +8,7 @@ class Hash
8
8
  return answer if answer
9
9
  end
10
10
 
11
- false
11
+ nil
12
12
  end
13
13
 
14
14
  end
@@ -0,0 +1,16 @@
1
+ class String
2
+
3
+ # The NumberRegex belows comes from the Rubinius source code and
4
+ # identifies both integers and floats correctly.
5
+
6
+ NumberRegex = /^\s*[+-]?((\d+_?)*\d+(\.(\d+_?)*\d+)?|\.(\d+_?)*\d+)(\s*|([eE][+-]?(\d+_?)*\d+)\s*)$/
7
+
8
+ def is_nan?
9
+ self !~ NumberRegex
10
+ end
11
+
12
+ def is_num?
13
+ !is_nan?
14
+ end
15
+
16
+ end
@@ -1,18 +1,52 @@
1
1
  Kernel.module_eval do
2
2
 
3
- def new_job(_method)
3
+ # BEWARE: _self is currently not accepted in perform_later jobs due to serialization errors
4
+
5
+ # The cases of 'id' and '_self' both handle instances, with the difference
6
+ # being that 'id' works for objects that have a database record, while '_self'
7
+ # works for non database supported instanes, such as an Exporter instance.
8
+
9
+ def new_job(_method, *args, **kwargs)
4
10
 
5
11
  if instance_methods(false).include? _method
6
- define_method "#{_method}_job" do
7
- Eitil::SingleMethodJob.perform_later(_class: self.class.to_s, _method: _method.to_s, id: id)
12
+ define_method "#{_method}_job" do |_self = nil, *args, **kwargs|
13
+
14
+ Eitil::SingleMethodJob.perform_later(
15
+ *args, _class: self.class.to_s, _method: _method.to_s, id: safe_send(:id), _self: self.to_json, **kwargs
16
+ )
8
17
  end
9
18
 
10
- elsif singleton_methods(false).include? _method
11
- define_singleton_method "#{_method}_job" do
12
- Eitil::SingleMethodJob.perform_later(_class: to_s, _method: _method.to_s)
19
+ elsif singleton_methods(false).include? _method
20
+ define_singleton_method "#{_method}_job" do |*args, **kwargs|
21
+
22
+ Eitil::SingleMethodJob.perform_later(
23
+ *args, _class: to_s, _method: _method.to_s, **kwargs
24
+ )
13
25
  end
14
- end
26
+ end
27
+ end
28
+
29
+ # BEWARE: This is an exact copy of the above method, except for .perform_now instead of .perform_later and the method's name.
30
+ # The reason for not using helper methods is to not unnecessarily fill and potentially fuck up the Kernel environment.
31
+
32
+ def new_job_debugger(_method, *args, **kwargs)
15
33
 
34
+ if instance_methods(false).include? _method
35
+ define_method "#{_method}_job_debugger" do |_self = nil, *args, **kwargs|
36
+
37
+ Eitil::SingleMethodJob.perform_now(
38
+ *args, _class: self.class.to_s, _method: _method.to_s, id: safe_send(:id), _self: self.to_json, **kwargs
39
+ )
40
+ end
41
+
42
+ elsif singleton_methods(false).include? _method
43
+ define_singleton_method "#{_method}_job_debugger" do |*args, **kwargs|
44
+
45
+ Eitil::SingleMethodJob.perform_now(
46
+ *args, _class: to_s, _method: _method.to_s, **kwargs
47
+ )
48
+ end
49
+ end
16
50
  end
17
51
 
18
52
  end
@@ -2,9 +2,23 @@ module Eitil
2
2
  class SingleMethodJob < ApplicationJob
3
3
  queue_as :default
4
4
 
5
- def perform(_class:, _method:, id: nil)
6
- object = id ? _class.constantize.find(id) : _class.constantize
7
- object.send _method
5
+ # BEWARE: _self is currently not accepted in perform_later jobs due to serialization errors
6
+
7
+ # The cases of 'id' and '_self' both handle instances, with the difference
8
+ # being that 'id' works for objects that have a database record, while '_self'
9
+ # works for non database supported instanes, such as an Exporter instance.
10
+
11
+ def perform(*args, _class:, _method:, id: nil, _self: nil, **kwargs)
12
+ object =
13
+ if id
14
+ _class.constantize.find(id)
15
+ elsif _self
16
+ _self
17
+ else
18
+ _class.constantize
19
+ end
20
+
21
+ object.send _method, *args, **kwargs
8
22
  end
9
23
  end
10
24
  end
@@ -2,86 +2,82 @@ module Eitil
2
2
  module DefaultScopes
3
3
  extend ActiveSupport::Concern
4
4
  included do
5
-
6
- SharableDateScopes = -> (column) {
7
- eitil_scope :"#{column}_today", -> { where("#{column} = ?", Date.today) }
8
- eitil_scope :"#{column}_past", -> { where("#{column} < ?", Date.today) }
9
- eitil_scope :"#{column}_future", -> { where("#{column} > ?", Date.today) }
10
-
11
- eitil_scope :"#{column}_on_date", -> (date) { where("#{column} = ?", date) }
12
- eitil_scope :"#{column}_before_date", -> (date) { where("#{column} = ?", date) }
13
- eitil_scope :"#{column}_after_date", -> (date) { where("#{column} = ?", date) }
14
- eitil_scope :"#{column}_between_dates", -> (from, till) { where("#{column} >= ? and #{column} <= ?", from, till) }
5
+ class << self
15
6
 
16
- eitil_scope :"#{column}_oldest_first", -> { order("#{column} ASC") }
17
- eitil_scope :"#{column}_newest_first", -> { order("#{column} DESC") }
18
- }
7
+ SharableDateScopes = -> (_class, column) {
8
+ _class.eitil_scope :"#{column}_today", -> { where("#{column} = ?", Date.today) }
9
+ _class.eitil_scope :"#{column}_past", -> { where("#{column} < ?", Date.today) }
10
+ _class.eitil_scope :"#{column}_future", -> { where("#{column} > ?", Date.today) }
11
+
12
+ _class.eitil_scope :"#{column}_on_date", -> (date) { where("#{column} = ?", date) }
13
+ _class.eitil_scope :"#{column}_before_date", -> (date) { where("#{column} = ?", date) }
14
+ _class.eitil_scope :"#{column}_after_date", -> (date) { where("#{column} = ?", date) }
15
+ _class.eitil_scope :"#{column}_between_dates", -> (from, till) { where("#{column} >= ? and #{column} <= ?", from, till) }
19
16
 
20
- SharableNumScopes = -> (column) {
21
- eitil_scope :"#{column}_equal_to", -> (number) { where("#{column} = ?", number) }
22
- eitil_scope :"#{column}_lower_than", -> (number) { where("#{column} = <", number) }
23
- eitil_scope :"#{column}_higher_than", -> (number) { where("#{column} = >", number) }
24
- eitil_scope :"#{column}_between", -> (min, max) { where("#{column} >= ? and #{column} <= ?", min, max) }
17
+ _class.eitil_scope :"#{column}_oldest_first", -> { order("#{column} ASC") }
18
+ _class.eitil_scope :"#{column}_newest_first", -> { order("#{column} DESC") }
19
+ }
25
20
 
26
- eitil_scope :"#{column}_ascending", -> { order("#{column} ASC") }
27
- eitil_scope :"#{column}_descending", -> { order("#{column} DESC") }
28
- }
21
+ SharableNumScopes = -> (_class, column) {
22
+ _class.eitil_scope :"#{column}_equal_to", -> (number) { where("#{column} = ?", number) }
23
+ _class.eitil_scope :"#{column}_lower_than", -> (number) { where("#{column} = <", number) }
24
+ _class.eitil_scope :"#{column}_higher_than", -> (number) { where("#{column} = >", number) }
25
+ _class.eitil_scope :"#{column}_between", -> (min, max) { where("#{column} >= ? and #{column} <= ?", min, max) }
29
26
 
30
- class << self
27
+ _class.eitil_scope :"#{column}_ascending", -> { order("#{column} ASC") }
28
+ _class.eitil_scope :"#{column}_descending", -> { order("#{column} DESC") }
29
+ }
31
30
 
32
- private
33
-
34
- def self.inherited(subclass)
35
- use_eitil_scopes
36
- super
37
- end
31
+ def inherited(subclass)
32
+ super
33
+ subclass.use_eitil_scopes
34
+ end
38
35
 
39
- def use_eitil_scopes
40
- return if abstract_class?
41
- %i[boolean datetime date integer float].each { |_type| send :"create_eitil_#{_type}_scopes" }
42
- end
36
+ def use_eitil_scopes
37
+ return if abstract_class?
38
+ %i[boolean datetime date integer float].each { |_type| send :"create_eitil_#{_type}_scopes" }
39
+ end
43
40
 
44
- def eitil_scope(_name, _proc)
45
- scope _name, _proc unless respond_to? _name
46
- end
47
-
48
- def columns_of_type(data_type)
49
- columns_hash.select { |column,v| v.sql_type_metadata.type == data_type }
50
- end
41
+ def eitil_scope(_name, _proc)
42
+ scope _name, _proc unless respond_to? _name
43
+ end
44
+
45
+ def columns_of_type(data_type)
46
+ columns_hash.select { |column,v| v.sql_type_metadata.type == data_type }
47
+ end
51
48
 
52
- def create_eitil_boolean_scopes
53
- columns_of_type(:boolean)&.map do |column, object|
54
- eitil_scope :"#{column}_true", -> { where(column => true) }
55
- eitil_scope :"#{column}_false", -> { where(column => [false, nil]) }
49
+ def create_eitil_boolean_scopes
50
+ columns_of_type(:boolean)&.map do |column, object|
51
+ eitil_scope :"#{column}_true", -> { where(column => true) }
52
+ eitil_scope :"#{column}_false", -> { where(column => [false, nil]) }
53
+ end
56
54
  end
57
- end
58
55
 
59
- def create_eitil_datetime_scopes
60
- columns_of_type(:datetime)&.map do |column, object|
61
- SharableDateScopes.call column
56
+ def create_eitil_datetime_scopes
57
+ columns_of_type(:datetime)&.map do |column, object|
58
+ SharableDateScopes.call self, column
59
+ end
62
60
  end
63
- end
64
61
 
65
- def create_eitil_date_scopes
66
- columns_of_type(:date)&.map do |column, object|
67
- SharableDateScopes.call column
62
+ def create_eitil_date_scopes
63
+ columns_of_type(:date)&.map do |column, object|
64
+ SharableDateScopes.call self, column
65
+ end
68
66
  end
69
- end
70
67
 
71
- def create_eitil_integer_scopes
72
- columns_of_type(:integer)&.map do |column, object|
73
- SharableNumScopes.call column
68
+ def create_eitil_integer_scopes
69
+ columns_of_type(:integer)&.map do |column, object|
70
+ SharableNumScopes.call self, column
71
+ end
74
72
  end
75
- end
76
73
 
77
- def create_eitil_float_scopes
78
- columns_of_type(:float)&.map do |column, object|
79
- SharableNumScopes.call column
74
+ def create_eitil_float_scopes
75
+ columns_of_type(:float)&.map do |column, object|
76
+ SharableNumScopes.call self, column
77
+ end
80
78
  end
81
- end
82
79
 
83
80
  end
84
-
85
81
  end
86
82
  end
87
83
  end
data/lib/eitil/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eitil
2
- VERSION = '0.3.3'
2
+ VERSION = '0.3.8'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eitil
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jurriaan Schrofer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-18 00:00:00.000000000 Z
11
+ date: 2021-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -52,6 +52,10 @@ files:
52
52
  - app/jobs/eitil/application_job.rb
53
53
  - app/mailers/eitil/application_mailer.rb
54
54
  - app/models/eitil/application_record.rb
55
+ - app/models/eitil/stack_trace/audit.rb
56
+ - app/models/eitil/stack_trace/call.rb
57
+ - app/models/eitil/stack_trace/stack.rb
58
+ - config/initializers/modules/dir.rb
55
59
  - config/initializers/monkeys/application_controller.rb
56
60
  - config/initializers/monkeys/application_record.rb
57
61
  - config/initializers/monkeys/date_time.rb
@@ -59,6 +63,7 @@ files:
59
63
  - config/initializers/monkeys/kernel.rb
60
64
  - config/initializers/monkeys/module.rb
61
65
  - config/initializers/monkeys/object.rb
66
+ - config/initializers/monkeys/string.rb
62
67
  - config/initializers/wrappers/decorators/application_decorator.rb
63
68
  - config/initializers/wrappers/decorators/controller_decorator.rb
64
69
  - config/initializers/wrappers/jobs/active_job_macros.rb