bonobot 0.0.9 ā†’ 0.1.0

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: 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: