active_analysis 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2264c818bb6bbdf31ecde9797cbeb77edf1f42b52d3b7f3f0178fbf47fec2ef8
4
+ data.tar.gz: 8cf368194ab3226945d275fea222685b346c6c6821dddde0ad9ddcdea40ca445
5
+ SHA512:
6
+ metadata.gz: e9381a23b549ef234a7d4e13aa04460b99d6365b1f82f6cd3359d8d4b31e72d7be3664ee64536ff73429353c83122f5a0f113b64ebd104c530f1721cb1ed363e
7
+ data.tar.gz: c9f3f4ce840c7b1cfae253459f09af28163672fff60c1d0643f45f256d3b08d4689752de359d47923e883c1e43abb9a6e33a91c8089ea27a26b7e95a72dc5710
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2021-05-01
4
+
5
+ - Initial release
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2021 Breno Gazzola
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Active Analysis
2
+
3
+ A collection of active storage analyzers
4
+
5
+ [![active-analysis-main](https://github.com/FestaLab/active_analysis/actions/workflows/main.yml/badge.svg)](https://github.com/FestaLab/active_analysis/actions/workflows/main.yml)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'active_analysis'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ ## Usage
20
+
21
+ Active Analyzers will automatically add all its analyzers to Active Storage's analyzers array. Don't worry, if you added any custom analyzers they will be there. You can check the comments in the source code of each analyzer to see what information they extract from files:
22
+ - Audio: [source](https://github.com/FestaLab/active_analysis/blob/main/lib/active_analysis/analyzer/audio_analyzer.rb)
23
+ - Image: [source](https://github.com/FestaLab/active_analysis/blob/main/lib/active_analysis/analyzer/image_analyzer.rb)
24
+ - PDF: [source](https://github.com/FestaLab/active_analysis/blob/main/lib/active_analysis/analyzer/pdf_analyzer.rb)
25
+ - Video: [source](https://github.com/FestaLab/active_analysis/blob/main/lib/active_analysis/analyzer/video_analyzer.rb)
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/FestaLab/active_analysis. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/FestaLab/active_analysis/blob/main/CODE_OF_CONDUCT.md).
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
40
+
41
+ ## Code of Conduct
42
+
43
+ Everyone interacting in the ActiveAnalysis project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/FestaLab/active_analysis/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+
5
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
6
+
7
+ load "rails/tasks/engine.rake"
8
+ load "rails/tasks/statistics.rake"
9
+
10
+ require "bundler/gem_tasks"
11
+ require "rake/testtask"
12
+
13
+ Rake::TestTask.new(:test) do |t|
14
+ t.libs << "test"
15
+ t.pattern = "test/**/*_test.rb"
16
+ t.verbose = false
17
+ end
18
+
19
+ task default: :test
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/active_analysis .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module ActiveAnalysis
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ActiveAnalysis
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ActiveAnalysis
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module ActiveAnalysis
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveAnalysis
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Active analysis</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "active_analysis/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ ActiveAnalysis::Engine.routes.draw do
2
+ end
@@ -0,0 +1,12 @@
1
+ require "active_analysis/version"
2
+ require "active_analysis/engine"
3
+
4
+ module ActiveAnalysis
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :FixtureSet
8
+
9
+ mattr_accessor :logger
10
+ mattr_accessor :analyzers
11
+ mattr_accessor :image_library
12
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAnalysis
4
+ # This is an abstract base class for analyzers, which extract metadata from blobs. See
5
+ # Analyzer::AudioAnalyzer for an example of a concrete subclass.
6
+ class Analyzer < ActiveStorage::Analyzer
7
+ end
8
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAnalysis
4
+ # Extracts duration (seconds) and bit_rate (bits/s) from an audio blob.
5
+ #
6
+ # Example:
7
+ #
8
+ # ActiveStorage::Analyzer::AudioAnalyzer.new(blob).metadata
9
+ # # => { duration: 5.0, bit_rate: 320340 }
10
+ #
11
+ # This analyzer requires the {FFmpeg}[https://www.ffmpeg.org] system library, which is not provided by Rails.
12
+ class Analyzer::AudioAnalyzer < Analyzer
13
+ def self.accept?(blob)
14
+ blob.audio?
15
+ end
16
+
17
+ def metadata
18
+ { duration: duration, bit_rate: bit_rate }.compact
19
+ end
20
+
21
+ private
22
+ def duration
23
+ duration = audio_stream["duration"]
24
+ Float(duration) if duration
25
+ end
26
+
27
+ def bit_rate
28
+ bit_rate = audio_stream["bit_rate"]
29
+ Integer(bit_rate) if bit_rate
30
+ end
31
+
32
+ def audio_stream
33
+ @audio_stream ||= streams.detect { |stream| stream["codec_type"] == "audio" } || {}
34
+ end
35
+
36
+ def streams
37
+ probe["streams"] || []
38
+ end
39
+
40
+ def probe
41
+ @probe ||= download_blob_to_tempfile { |file| probe_from(file) }
42
+ end
43
+
44
+ def probe_from(file)
45
+ IO.popen([ffprobe_path,
46
+ "-print_format", "json",
47
+ "-show_streams",
48
+ "-show_format",
49
+ "-v", "error",
50
+ file.path
51
+ ]) do |output|
52
+ JSON.parse(output.read)
53
+ end
54
+ rescue Errno::ENOENT
55
+ logger.info "Skipping audio analysis because FFmpeg isn't installed"
56
+ {}
57
+ end
58
+
59
+ def ffprobe_path
60
+ ActiveStorage.paths[:ffprobe] || "ffprobe"
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAnalysis
4
+ # This is an abstract base class for image analyzers, which extract width and height from an image blob.
5
+ #
6
+ # If the image contains EXIF data indicating its angle is 90 or 270 degrees, its width and height are swapped for convenience.
7
+ #
8
+ # Example:
9
+ #
10
+ # ActiveAnalysis::CoreExtensionsAnalyzer::ImageAnalyzer::ImageMagick.new(blob).metadata
11
+ # # => { width: 4104, height: 2736 }
12
+ class Analyzer::ImageAnalyzer < Analyzer
13
+ def self.accept?(blob)
14
+ blob.image?
15
+ end
16
+
17
+ def metadata
18
+ read_image do |image|
19
+ if rotated_image?(image)
20
+ { width: image.height, height: image.width }
21
+ else
22
+ { width: image.width, height: image.height }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAnalysis
4
+ # This analyzer relies on the third-party {MiniMagick}[https://github.com/minimagick/minimagick] gem. MiniMagick requires
5
+ # the {ImageMagick}[http://www.imagemagick.org] system library.
6
+ class Analyzer::ImageAnalyzer::ImageMagick < Analyzer::ImageAnalyzer
7
+ def self.accept?(blob)
8
+ super && ActiveStorage.variant_processor == :mini_magick
9
+ end
10
+
11
+ private
12
+ def read_image
13
+ download_blob_to_tempfile do |file|
14
+ require "mini_magick"
15
+ image = MiniMagick::Image.new(file.path)
16
+
17
+ if image.valid?
18
+ yield image
19
+ else
20
+ logger.info "Skipping image analysis because ImageMagick doesn't support the file"
21
+ {}
22
+ end
23
+ end
24
+ rescue LoadError
25
+ logger.info "Skipping image analysis because the mini_magick gem isn't installed"
26
+ {}
27
+ rescue MiniMagick::Error => error
28
+ logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
29
+ {}
30
+ end
31
+
32
+ def rotated_image?(image)
33
+ %w[ RightTop LeftBottom TopRight BottomLeft ].include?(image["%[orientation]"])
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAnalysis
4
+ # This analyzer relies on the third-party {ruby-vips}[https://github.com/libvips/ruby-vips] gem. Ruby-vips requires
5
+ # the {libvips}[https://libvips.github.io/libvips/] system library.
6
+ class Analyzer::ImageAnalyzer::Vips < Analyzer::ImageAnalyzer
7
+ def self.accept?(blob)
8
+ super && ActiveStorage.variant_processor == :vips
9
+ end
10
+
11
+ private
12
+ def read_image
13
+ download_blob_to_tempfile do |file|
14
+ require "ruby-vips"
15
+ image = ::Vips::Image.new_from_file(file.path, access: :sequential)
16
+
17
+ if valid_image?(image)
18
+ yield image
19
+ else
20
+ logger.info "Skipping image analysis because Vips doesn't support the file"
21
+ {}
22
+ end
23
+ end
24
+ rescue LoadError
25
+ logger.info "Skipping image analysis because the ruby-vips gem isn't installed"
26
+ {}
27
+ rescue ::Vips::Error => error
28
+ logger.error "Skipping image analysis due to an Vips error: #{error.message}"
29
+ {}
30
+ end
31
+
32
+ ROTATIONS = /Right-top|Left-bottom|Top-right|Bottom-left/
33
+
34
+ def rotated_image?(image)
35
+ ROTATIONS === image.get("exif-ifd0-Orientation")
36
+ rescue ::Vips::Error
37
+ false
38
+ end
39
+
40
+ def valid_image?(image)
41
+ image.avg
42
+ true
43
+ rescue ::Vips::Error
44
+ false
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAnalysis
4
+ # Extracts width, height in pixels and number of pages from a pdf blob.
5
+ #
6
+ # Example:
7
+ #
8
+ # ActiveAnalysis::CoreExtensionsAnalyzer::PDFAnalyzer::Poppler.new(blob).metadata
9
+ # # => { width: 4104, height: 2736, pages: 10 }
10
+ #
11
+ # This analyzer requires the {poppler}[https://poppler.freedesktop.org/] system library, which is not provided by Rails.
12
+ class Analyzer::PDFAnalyzer < Analyzer
13
+ class << self
14
+ def accept?(blob)
15
+ blob.content_type == "application/pdf" && pdfinfo_exists?
16
+ end
17
+
18
+ def pdfinfo_path
19
+ ActiveStorage.paths[:pdfinfo] || "pdfinfo"
20
+ end
21
+
22
+ def pdfinfo_exists?
23
+ return @pdfinfo_exists if defined?(@pdfinfo_exists)
24
+
25
+ @pdfinfo_exists = system(pdfinfo_path, "-v", out: File::NULL, err: File::NULL)
26
+ end
27
+ end
28
+
29
+ def metadata
30
+ { width: width, height: height, pages: pages }.compact
31
+ end
32
+
33
+ private
34
+ def pages
35
+ pages = info["Pages"]
36
+ Integer(pages) if pages
37
+ end
38
+
39
+ def width
40
+ (right - left).floor if cropbox.present?
41
+ end
42
+
43
+ def height
44
+ (top - bottom).floor if cropbox.present?
45
+ end
46
+
47
+ def left
48
+ Float cropbox[0]
49
+ end
50
+
51
+ def bottom
52
+ Float cropbox[1]
53
+ end
54
+
55
+ def right
56
+ Float cropbox[2]
57
+ end
58
+
59
+ def top
60
+ Float cropbox[3]
61
+ end
62
+
63
+ def cropbox
64
+ return @cropbox if defined?(@cropbox)
65
+ @cropbox = (info["CropBox"] || "").split
66
+ end
67
+
68
+ def info
69
+ @info ||= download_blob_to_tempfile { |file| info_from(file) }
70
+ end
71
+
72
+ def info_from(file)
73
+ IO.popen([self.class.pdfinfo_path, "-box", file.path]) do |output|
74
+ output.read.scan(/^(.*?): *(.*)?/).to_h
75
+ end
76
+ rescue Errno::ENOENT
77
+ logger.info "Skipping pdf analysis due to an error"
78
+ {}
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAnalysis
4
+ # Extracts the following from a video blob:
5
+ #
6
+ # * Width (pixels)
7
+ # * Height (pixels)
8
+ # * Duration (seconds)
9
+ # * Angle (degrees)
10
+ # * Display aspect ratio
11
+ # * Audio (true if file has an audio channel, false if not)
12
+ # * Video (true if file has an video channel, false if not)
13
+ #
14
+ # Example:
15
+ #
16
+ # ActiveStorage::Analyzer::VideoAnalyzer.new(blob).metadata
17
+ # # => { width: 640.0, height: 480.0, duration: 5.0, angle: 0, display_aspect_ratio: [4, 3], audio: true, video: true }
18
+ #
19
+ # When a video's angle is 90 or 270 degrees, its width and height are automatically swapped for convenience.
20
+ #
21
+ # This analyzer requires the {FFmpeg}[https://www.ffmpeg.org] system library, which is not provided by Rails.
22
+ class Analyzer::VideoAnalyzer < Analyzer
23
+ def self.accept?(blob)
24
+ blob.video?
25
+ end
26
+
27
+ def metadata
28
+ { width: width, height: height, duration: duration, angle: angle, display_aspect_ratio: display_aspect_ratio, audio: audio?, video: video? }.compact
29
+ end
30
+
31
+ private
32
+ def width
33
+ if rotated?
34
+ computed_height || encoded_height
35
+ else
36
+ encoded_width
37
+ end
38
+ end
39
+
40
+ def height
41
+ if rotated?
42
+ encoded_width
43
+ else
44
+ computed_height || encoded_height
45
+ end
46
+ end
47
+
48
+ def duration
49
+ duration = video_stream["duration"] || container["duration"]
50
+ Float(duration) if duration
51
+ end
52
+
53
+ def angle
54
+ Integer(tags["rotate"]) if tags["rotate"]
55
+ end
56
+
57
+ def display_aspect_ratio
58
+ if descriptor = video_stream["display_aspect_ratio"]
59
+ if terms = descriptor.split(":", 2)
60
+ numerator = Integer(terms[0])
61
+ denominator = Integer(terms[1])
62
+
63
+ [numerator, denominator] unless numerator == 0
64
+ end
65
+ end
66
+ end
67
+
68
+ def rotated?
69
+ angle == 90 || angle == 270
70
+ end
71
+
72
+ def audio?
73
+ audio_stream.present?
74
+ end
75
+
76
+ def video?
77
+ video_stream.present? && !video_stream["codec_name"].in?(["jpg", "png"])
78
+ end
79
+
80
+ def computed_height
81
+ if encoded_width && display_height_scale
82
+ encoded_width * display_height_scale
83
+ end
84
+ end
85
+
86
+ def encoded_width
87
+ @encoded_width ||= Float(video_stream["width"]) if video_stream["width"]
88
+ end
89
+
90
+ def encoded_height
91
+ @encoded_height ||= Float(video_stream["height"]) if video_stream["height"]
92
+ end
93
+
94
+ def display_height_scale
95
+ @display_height_scale ||= Float(display_aspect_ratio.last) / display_aspect_ratio.first if display_aspect_ratio
96
+ end
97
+
98
+ def tags
99
+ @tags ||= video_stream["tags"] || {}
100
+ end
101
+
102
+ def video_stream
103
+ @video_stream ||= streams.detect { |stream| stream["codec_type"] == "video" } || {}
104
+ end
105
+
106
+ def audio_stream
107
+ @audio_stream ||= streams.detect { |stream| stream["codec_type"] == "audio" } || {}
108
+ end
109
+
110
+ def streams
111
+ probe["streams"] || []
112
+ end
113
+
114
+ def container
115
+ probe["format"] || {}
116
+ end
117
+
118
+ def probe
119
+ @probe ||= download_blob_to_tempfile { |file| probe_from(file) }
120
+ end
121
+
122
+ def probe_from(file)
123
+ IO.popen([ffprobe_path,
124
+ "-print_format", "json",
125
+ "-show_streams",
126
+ "-show_format",
127
+ "-v", "error",
128
+ file.path
129
+ ]) do |output|
130
+ JSON.parse(output.read)
131
+ end
132
+ rescue Errno::ENOENT
133
+ logger.info "Skipping video analysis because FFmpeg isn't installed"
134
+ {}
135
+ end
136
+
137
+ def ffprobe_path
138
+ ActiveStorage.paths[:ffprobe] || "ffprobe"
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_storage"
4
+
5
+ require "marcel"
6
+ require "ruby-vips"
7
+ require "mini_magick"
8
+
9
+ require_relative "analyzer"
10
+ require_relative "analyzer/image_analyzer"
11
+ require_relative "analyzer/image_analyzer/vips"
12
+ require_relative "analyzer/image_analyzer/image_magick"
13
+ require_relative "analyzer/audio_analyzer"
14
+ require_relative "analyzer/video_analyzer"
15
+ require_relative "analyzer/pdf_analyzer"
16
+
17
+ module ActiveAnalysis
18
+ class Engine < ::Rails::Engine
19
+ isolate_namespace ActiveAnalysis
20
+
21
+ config.active_analysis = ActiveSupport::OrderedOptions.new
22
+ config.eager_load_namespaces << ActiveAnalysis
23
+
24
+ initializer "active_analysis.configs" do
25
+ config.after_initialize do |app|
26
+ ActiveAnalysis.logger = app.config.active_analysis.logger || Rails.logger
27
+ ActiveAnalysis.analyzers = app.config.active_analysis.analyzers || []
28
+ ActiveAnalysis.image_library = app.config.active_analysis.image_library || app.config.active_storage.variant_processor
29
+ end
30
+ end
31
+
32
+ initializer "active_analysis.core_extensions" do
33
+ config.after_initialize do |app|
34
+ app.config.active_storage.analyzers.delete ActiveStorage::Analyzer::ImageAnalyzer
35
+ app.config.active_storage.analyzers.delete ActiveStorage::Analyzer::VideoAnalyzer
36
+
37
+ app.config.active_storage.analyzers.append Analyzer::ImageAnalyzer::Vips
38
+ app.config.active_storage.analyzers.append Analyzer::ImageAnalyzer::ImageMagick
39
+ app.config.active_storage.analyzers.append Analyzer::VideoAnalyzer
40
+ app.config.active_storage.analyzers.append Analyzer::AudioAnalyzer
41
+ app.config.active_storage.analyzers.append Analyzer::PDFAnalyzer
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAnalysis
4
+ # Returns the version of the currently loaded Active Storage as a <tt>Gem::Version</tt>.
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ module VERSION
10
+ MAJOR = 0
11
+ MINOR = 1
12
+ TINY = 2
13
+ PRE = nil
14
+
15
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "gem_version"
4
+
5
+ module ActiveAnalysis
6
+ # Returns the version of the currently loaded ActiveStorage as a <tt>Gem::Version</tt>
7
+ def self.version
8
+ gem_version
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :active_analysis do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,226 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_analysis
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Breno Gazzola
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-06-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activestorage
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '6.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '6.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mini_magick
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '4.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '4.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby-vips
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: platform_agent
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '11.1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '11.1'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.14'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.14'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-performance
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.11'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.11'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-packaging
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.5'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.5'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop-rails
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2.10'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2.10'
167
+ description:
168
+ email:
169
+ - breno@festalab.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - CHANGELOG.md
175
+ - MIT-LICENSE
176
+ - README.md
177
+ - Rakefile
178
+ - app/assets/config/active_analysis_manifest.js
179
+ - app/assets/stylesheets/active_analysis/application.css
180
+ - app/controllers/active_analysis/application_controller.rb
181
+ - app/helpers/active_analysis/application_helper.rb
182
+ - app/jobs/active_analysis/application_job.rb
183
+ - app/mailers/active_analysis/application_mailer.rb
184
+ - app/models/active_analysis/application_record.rb
185
+ - app/views/layouts/active_analysis/application.html.erb
186
+ - config/routes.rb
187
+ - lib/active_analysis.rb
188
+ - lib/active_analysis/analyzer.rb
189
+ - lib/active_analysis/analyzer/audio_analyzer.rb
190
+ - lib/active_analysis/analyzer/image_analyzer.rb
191
+ - lib/active_analysis/analyzer/image_analyzer/image_magick.rb
192
+ - lib/active_analysis/analyzer/image_analyzer/vips.rb
193
+ - lib/active_analysis/analyzer/pdf_analyzer.rb
194
+ - lib/active_analysis/analyzer/video_analyzer.rb
195
+ - lib/active_analysis/engine.rb
196
+ - lib/active_analysis/gem_version.rb
197
+ - lib/active_analysis/version.rb
198
+ - lib/tasks/active_analysis_tasks.rake
199
+ homepage: https://github.com/FestaLab/active_analysis
200
+ licenses:
201
+ - MIT
202
+ metadata:
203
+ allowed_push_host: https://rubygems.org
204
+ homepage_uri: https://github.com/FestaLab/active_analysis
205
+ source_code_uri: https://github.com/FestaLab/active_analysis
206
+ changelog_uri: https://github.com/FestaLab/active_analysis/CHANGELOG.mg
207
+ post_install_message:
208
+ rdoc_options: []
209
+ require_paths:
210
+ - lib
211
+ required_ruby_version: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: 2.5.0
216
+ required_rubygems_version: !ruby/object:Gem::Requirement
217
+ requirements:
218
+ - - ">="
219
+ - !ruby/object:Gem::Version
220
+ version: '0'
221
+ requirements: []
222
+ rubygems_version: 3.0.3
223
+ signing_key:
224
+ specification_version: 4
225
+ summary: Collection of Active Storage analyzers
226
+ test_files: []