bonobot 0.0.9 → 0.1.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
  SHA256:
3
- metadata.gz: e09dd5420ba03ab108dd23316f5171ad5f402d0075af929391b40b6ca4cf066c
4
- data.tar.gz: 6ec4202d42ee696375c4377da3c957ff1b67fe4a92dbe8c2a3361a523e21cf64
3
+ metadata.gz: 541fce28b33f9efe5631c3ee2c91b7e5ee61c5cf2b9d33913790d6575fd46388
4
+ data.tar.gz: 306f344425e0f65aa3e19b30fa721bdbf91b561e56f68fd4e07273a861140c46
5
5
  SHA512:
6
- metadata.gz: b37d57570d73e78dfecb0a5e65ed4171552593b81f1588418cc3653d24133aff4468831cda0a293c3b249d2faebd5cdcd2ae7632af6ca7ad3e6f79805979c0cb
7
- data.tar.gz: a368a1f128a152fd0928057a6b4e564b1a79d3913a80db48bb8a05b2a14a25c9c0bb5c630722668cd22f87cfaf80c34309bd37dae98da3d335f493e3bba4f0a4
6
+ metadata.gz: b3a503f11f950f2e8f0e241555a71308024a1a7a18a9d0808887a81cf49d6f3d8a9ec1fab38eff9578d73af6f83b7c6a5811d85f342df8dfe9209517bb0c18af
7
+ data.tar.gz: 68c51c580b004f6de15cfc2568b412312e5195cb317d271061b4717e75b943f09ba2da3cea4df959559357e14c1437ef8f6883d70f84d1ee80c07e8f6e05277a
data/README.md CHANGED
@@ -8,13 +8,14 @@ BonoBot is a Ruby gem that helps with Rails monkey patching.
8
8
  ### Status
9
9
  #### Generate all status:
10
10
  ```bash
11
- bundle exec rake bonobot: status
11
+ bundle exec rake bonobot:status
12
12
  ```
13
13
  #### Generate a specific status:
14
14
  ```bash
15
- bundle exec rake bonobot:status:out_of_date
16
15
  bundle exec rake bonobot:status:up_to_date
17
- bundle exec rake bonobot:update_out_of_date
16
+ bundle exec rake bonobot:status:out_of_date
17
+ bundle exec rake bonobot:status:missing
18
+ bundle exec rake bonobot:status:unused
18
19
  ```
19
20
 
20
21
  ### Add missing
@@ -27,6 +28,11 @@ bundle exec rake bonobot:add_missing
27
28
  bundle exec rake bonobot:update_out_of_date
28
29
  ```
29
30
 
31
+ ### Customization
32
+ ```bash
33
+ bundle exec rake bonobot:install
34
+ ```
35
+
30
36
  ## Installation
31
37
  Add this line to your application's Gemfile:
32
38
 
@@ -21,7 +21,7 @@ module Bonobot
21
21
  if f.first == "# frozen_string_literal: true"
22
22
  f.insert(1, "\n#{annotation}")
23
23
  else
24
- f.insert(0, "\n#{annotation}")
24
+ f.insert(0, annotation)
25
25
  end
26
26
 
27
27
  File.write(@path, "#{f.join("\n")}\n")
@@ -39,7 +39,7 @@ module Bonobot
39
39
 
40
40
  def annotation
41
41
  if @path.to_s.end_with?(".erb")
42
- "<%# bonobot_fingerprint: #{@fingerprint} %>"
42
+ "<%# bonobot_fingerprint: #{@fingerprint} %>\n"
43
43
  else
44
44
  "# bonobot_fingerprint: #{@fingerprint}"
45
45
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bonobot::Configuration
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+
13
+ def configure
14
+ yield(configuration)
15
+ end
16
+ end
17
+
18
+ class Configuration
19
+ attr_accessor :included_dirs, :files_pattern, :excluded_files, :fingerprint_algorithm, :fingerprint_human_readable
20
+
21
+ def initialize
22
+ @status_file_path = config_value_for("status_file_path", Rails.root)
23
+ @status_file_name = "#{config_value_for("status_file_name", "status")}.json"
24
+ @included_dirs = "{#{config_value_for("included_dirs", ["app"]).join(",")}}"
25
+ @files_pattern = "{#{config_value_for("files_pattern", %w(rb erb)).join(",")}}"
26
+ @excluded_files = config_value_for("excluded_files", [])
27
+ @fingerprint_algorithm = config_value_for("fingerprint_algorithm", "md5")
28
+ @fingerprint_human_readable = config_value_for("fingerprint_human_readable", false)
29
+ end
30
+
31
+ def status_file
32
+ File.join(@status_file_path, @status_file_name)
33
+ end
34
+
35
+ def self.config_file
36
+ @config_file ||= File.exist?(Rails.root.join(".bonobot.yml")) ? YAML.load_file(Rails.root.join(".bonobot.yml")) : {}
37
+ end
38
+
39
+ def config_value_for(key, default_value)
40
+ self.class.config_file.fetch(key, default_value)
41
+ end
42
+ end
43
+ end
@@ -2,17 +2,14 @@
2
2
 
3
3
  module Bonobot
4
4
  class EngineFile
5
- attr_reader :path, :engine_name, :short_path, :root_path
5
+ attr_reader :path, :engine_name, :short_path, :root_path, :fingerprint
6
6
 
7
7
  def initialize(path, engine)
8
8
  @path = path
9
9
  @root_path = engine.instance.root
10
10
  @engine_name = engine_to_name(engine)
11
11
  @short_path = path.sub("#{@root_path}/", "")
12
- end
13
-
14
- def fingerprint
15
- Digest::MD5.hexdigest(File.read(@path))
12
+ @fingerprint = Bonobot::Fingerprint.calculate(path)
16
13
  end
17
14
 
18
15
  def to_hash
@@ -2,13 +2,18 @@
2
2
 
3
3
  module Bonobot
4
4
  class EnginesFilesRegistry
5
+ include Bonobot::Configuration
6
+ include Bonobot::Findable
7
+ include Bonobot::Outputable
8
+ include Bonobot::Reloadable
9
+
5
10
  def self.all
6
- @all ||= deduplicate(generate)
11
+ @all ||= deduplicate(generate).reject { |engine_file| configuration.excluded_files.include?(engine_file.short_path) }
7
12
  end
8
13
 
9
14
  def self.generate
10
15
  Parallel.flat_map(::Rails::Engine.subclasses) do |klass|
11
- Dir.glob(root(klass.instance.root).join("**", "*.{erb,rb}")).map do |path|
16
+ Dir.glob(root(klass.instance.root).join("**", "*.#{file_pattern}")).map do |path|
12
17
  EngineFile.new(path, klass)
13
18
  end
14
19
  end
@@ -18,20 +23,12 @@ module Bonobot
18
23
  engine_files.group_by(&:path).map { |_, files| files.min_by(&:engine_name) }
19
24
  end
20
25
 
21
- def self.find_by(attributes)
22
- all.select do |local_file|
23
- attributes.all? do |key, value|
24
- local_file.try(key) == value
25
- end
26
- end
27
- end
28
-
29
- def self.output
30
- all.map(&:as_json)
26
+ def self.root(path)
27
+ Pathname.new(path).join(configuration.included_dirs)
31
28
  end
32
29
 
33
- def self.root(path)
34
- Pathname.new(path).join("app")
30
+ def self.file_pattern
31
+ configuration.files_pattern
35
32
  end
36
33
  end
37
34
  end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bonobot/overloads_registry"
4
- require "bonobot/annotator"
5
-
6
3
  module Bonobot
7
4
  class FilesOp
8
5
  def self.missing
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bonobot::Findable
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def find_by(attributes)
10
+ all.select do |local_file|
11
+ attributes.all? do |key, value|
12
+ local_file.try(key) == value
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "digest/bubblebabble"
5
+
6
+ module Bonobot::Fingerprint
7
+ include Bonobot::Configuration
8
+ ALGORITHM = { "md5" => Digest::MD5, "sha1" => Digest::SHA1, "sha256" => Digest::SHA256 }.freeze
9
+
10
+ def self.calculate(path)
11
+ algorithm.send(method, File.read(path))
12
+ end
13
+
14
+ def self.method
15
+ if configuration.fingerprint_human_readable
16
+ :bubblebabble
17
+ else
18
+ :hexdigest
19
+ end
20
+ end
21
+
22
+ def self.algorithm
23
+ ALGORITHM.fetch(configuration.fingerprint_algorithm, Digest::MD5)
24
+ end
25
+ end
@@ -1,25 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "parallel"
4
-
5
3
  module Bonobot
6
4
  class LocalFilesRegistry
5
+ include Bonobot::Configuration
6
+ include Bonobot::Outputable
7
+ include Bonobot::Reloadable
8
+
7
9
  def self.all
8
- @all ||= Parallel.map(Dir.glob(root.join("**", "*.{erb,rb}"))) do |path|
9
- LocalFile.new(path, rails_root)
10
- end
10
+ @all ||= Parallel.map(Dir.glob(root.join("**", "*.#{file_pattern}"))) { |path| LocalFile.new(path, ::Rails.root) }
11
+ .reject { |local_file| configuration.excluded_files.include?(local_file.path) }
11
12
  end
12
13
 
13
14
  def self.root
14
- rails_root.join("app")
15
- end
16
-
17
- def self.rails_root
18
- ::Rails.root
15
+ ::Rails.root.join(configuration.included_dirs)
19
16
  end
20
17
 
21
- def self.output
22
- all.map(&:as_json)
18
+ def self.file_pattern
19
+ configuration.files_pattern
23
20
  end
24
21
  end
25
22
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bonobot::Outputable
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def output
10
+ all.map(&:as_json)
11
+ end
12
+ end
13
+ end
@@ -14,6 +14,7 @@ module Bonobot
14
14
  end
15
15
 
16
16
  def status
17
+ return :unused if @engine_file.nil?
17
18
  return :missing if @local_file.annotation.nil?
18
19
  return :up_to_date if @local_file.annotation == @engine_file.fingerprint
19
20
 
@@ -2,25 +2,24 @@
2
2
 
3
3
  module Bonobot
4
4
  module OverloadsRegistry
5
+ include Bonobot::Findable
6
+ include Bonobot::Outputable
7
+ include Bonobot::Reloadable
8
+
5
9
  def self.all
6
10
  @all ||= LocalFilesRegistry.all.flat_map do |local_file|
7
- EnginesFilesRegistry.find_by(short_path: local_file.path).map do |engine_file|
8
- Overload.new(local_file, engine_file)
9
- end
10
- end
11
- end
11
+ next if local_file.nil?
12
12
 
13
- # TODO: Extract to module
14
- def self.find_by(attributes)
15
- all.select do |item|
16
- attributes.all? do |key, value|
17
- item.try(key) == value
18
- end
19
- end
20
- end
13
+ engines_files = EnginesFilesRegistry.find_by(short_path: local_file.path)
21
14
 
22
- def self.output
23
- all.map(&:as_json)
15
+ if engines_files.empty? && local_file.annotation.present?
16
+ Overload.new(local_file, nil)
17
+ else
18
+ engines_files.map do |engine_file|
19
+ Overload.new(local_file, engine_file)
20
+ end
21
+ end
22
+ end.compact
24
23
  end
25
24
  end
26
25
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bonobot::Reloadable
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def reload
10
+ @all = nil
11
+ end
12
+ end
13
+ end
@@ -4,52 +4,81 @@ require "json"
4
4
 
5
5
  module Bonobot
6
6
  class Status
7
- STATUS = { up_to_date: "🄳", out_of_date: "😱", missing: "🤬" }.freeze
7
+ include Bonobot::Configuration
8
+
9
+ STATUS = { up_to_date: "🄳", out_of_date: "😱", unused: "šŸ˜…", missing: "🤬" }.freeze
8
10
 
9
11
  def self.generate(status = nil)
10
- puts "-----"
11
- puts "šŸ™ˆ šŸ™‰ šŸ™Š Bonobot šŸ™ˆ šŸ™‰ šŸ™Š"
12
- puts "-----"
13
- puts "šŸ›  Generating status"
14
- File.write("status.json", status_json)
15
- puts File.expand_path("status.json")
16
- puts "-----"
17
-
18
- if status
19
- generate_status(status.to_sym, STATUS[status.to_sym])
20
- else
21
- STATUS.each do |status_type, emoji|
22
- generate_status(status_type, emoji)
23
- end
24
- end
12
+ new(status).generate
13
+ end
25
14
 
26
- puts "-----"
27
- OverloadsRegistry.find_by(status: :out_of_date).empty? && OverloadsRegistry.find_by(status: :missing).empty?
15
+ def initialize(status)
16
+ @status = status
28
17
  end
29
18
 
30
- def self.present(entries)
19
+ def generate
20
+ generate_status_file
21
+ puts display_banner
22
+ return_status_code
23
+ end
24
+
25
+ def present(entries)
31
26
  entries.map do |entry|
32
- " - #{entry.engine_file.engine_name}: #{entry.engine_file.short_path} (#{entry.engine_file.fingerprint})"
27
+ if entry.engine_file.nil?
28
+ " - #{entry.path} (unused)"
29
+ else
30
+ " - #{entry.engine_file.engine_name}: #{entry.engine_file.short_path} (#{entry.engine_file.fingerprint})"
31
+ end
33
32
  end.join("\n")
34
33
  end
35
34
 
36
- def self.generate_status(status, emoji)
37
- return if OverloadsRegistry.find_by(status: status).empty?
38
-
35
+ def generate_status(status, emoji)
39
36
  overload_status = OverloadsRegistry.find_by(status: status)
40
37
  status_to_text = status.to_s.capitalize.gsub("_", " ")
41
38
 
42
- puts "-> #{emoji} #{status_to_text} fingerprint (#{overload_status.count}):"
43
- puts present(OverloadsRegistry.find_by(status: status))
44
- puts ""
39
+ if overload_status.empty?
40
+ ["-> #{emoji} #{status_to_text} : All good! \n"]
41
+ else
42
+ ["-> #{emoji} #{status_to_text} fingerprint (#{overload_status.count}):", present(OverloadsRegistry.find_by(status: status)), ""]
43
+ end
45
44
  end
46
45
 
47
- def self.status_json
46
+ def status_json
48
47
  JSON.pretty_generate({
49
48
  rails_files: LocalFilesRegistry.output,
50
49
  engines_files: EnginesFilesRegistry.output,
51
50
  overloads: OverloadsRegistry.output
52
51
  })
53
52
  end
53
+
54
+ def generate_status_file
55
+ File.write(self.class.configuration.status_file, status_json)
56
+ end
57
+
58
+ def display_banner
59
+ [display_intro + display_status.join("\n") + display_outro].join("\n")
60
+ end
61
+
62
+ def display_intro
63
+ "-----\nšŸ™ˆ šŸ™‰ šŸ™Š Bonobot šŸ™ˆ šŸ™‰ šŸ™Š\n-----\n\nšŸ›  Generating status\n#{File.expand_path(self.class.configuration.status_file)}\n-----\n\n"
64
+ end
65
+
66
+ def display_status
67
+ if @status
68
+ generate_status(@status.to_sym, STATUS[@status.to_sym])
69
+ else
70
+ STATUS.map do |status_type, emoji|
71
+ generate_status(status_type, emoji)
72
+ end
73
+ end
74
+ end
75
+
76
+ def display_outro
77
+ "\n-----"
78
+ end
79
+
80
+ def return_status_code
81
+ OverloadsRegistry.find_by(status: :out_of_date).empty? && OverloadsRegistry.find_by(status: :missing).empty?
82
+ end
54
83
  end
55
84
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bonobot
4
- VERSION = "0.0.9"
4
+ VERSION = "0.1.0"
5
5
  end
data/lib/bonobot.rb CHANGED
@@ -12,4 +12,9 @@ module Bonobot
12
12
  autoload :Overload, "bonobot/overload"
13
13
  autoload :FilesOp, "bonobot/files_op"
14
14
  autoload :Annotator, "bonobot/annotator"
15
+ autoload :Configuration, "bonobot/configuration"
16
+ autoload :Findable, "bonobot/findable"
17
+ autoload :Outputable, "bonobot/outputable"
18
+ autoload :Reloadable, "bonobot/reloadable"
19
+ autoload :Fingerprint, "bonobot/fingerprint"
15
20
  end
@@ -26,6 +26,11 @@ namespace :bonobot do
26
26
  end
27
27
 
28
28
  task uptodate: :up_to_date
29
+
30
+ desc "Generate status for unused"
31
+ task unused: :environment do
32
+ Bonobot::Status.generate(:unused)
33
+ end
29
34
  end
30
35
 
31
36
  desc "Add missing fingerprint to local files"
@@ -40,4 +45,11 @@ namespace :bonobot do
40
45
 
41
46
  task update_outdated: :update_out_of_date
42
47
  task update: :update_out_of_date
48
+
49
+ desc "Install bonobot"
50
+ task install: :environment do
51
+ dir = Gem::Specification.find_by_name("bonobot").gem_dir
52
+ FileUtils.cp_r File.join(dir, "bonobot_configuration_example.yml"), ".bonobot.yml"
53
+ puts "Bonobot configuration installed at .bonobot.yml"
54
+ end
43
55
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bonobot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - armandfardeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-07 00:00:00.000000000 Z
11
+ date: 2023-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parallel
@@ -162,22 +162,26 @@ files:
162
162
  - Rakefile
163
163
  - lib/bonobot.rb
164
164
  - lib/bonobot/annotator.rb
165
+ - lib/bonobot/configuration.rb
165
166
  - lib/bonobot/engine_file.rb
166
167
  - lib/bonobot/engines_files_registry.rb
167
168
  - lib/bonobot/files_op.rb
169
+ - lib/bonobot/findable.rb
170
+ - lib/bonobot/fingerprint.rb
168
171
  - lib/bonobot/local_file.rb
169
172
  - lib/bonobot/local_files_registry.rb
173
+ - lib/bonobot/outputable.rb
170
174
  - lib/bonobot/overload.rb
171
175
  - lib/bonobot/overloads_registry.rb
172
176
  - lib/bonobot/railtie.rb
177
+ - lib/bonobot/reloadable.rb
173
178
  - lib/bonobot/status.rb
174
179
  - lib/bonobot/version.rb
175
180
  - lib/tasks/bonobot_tasks.rake
176
181
  homepage: https://github.com/armandfardeau/bonobo
177
182
  licenses:
178
183
  - MIT
179
- metadata:
180
- documentation_uri: https://github.com/armandfardeau/bonobo
184
+ metadata: {}
181
185
  post_install_message:
182
186
  rdoc_options: []
183
187
  require_paths: