cellscan 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.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/builds/cellscan/application.css +956 -0
  6. data/app/assets/builds/cellscan/application.js +6976 -0
  7. data/app/assets/builds/cellscan/application.js.map +7 -0
  8. data/app/assets/config/cellscan_manifest.js +1 -0
  9. data/app/assets/stylesheets/cellscan/application.css +12 -0
  10. data/app/assets/stylesheets/cellscan/application.tailwind.css +89 -0
  11. data/app/controllers/cellscan/application_controller.rb +6 -0
  12. data/app/controllers/cellscan/files_controller.rb +36 -0
  13. data/app/controllers/cellscan/welcome_controller.rb +6 -0
  14. data/app/helpers/cellscan/application_helper.rb +5 -0
  15. data/app/javascript/application.js +5 -0
  16. data/app/javascript/controllers/application.js +9 -0
  17. data/app/javascript/controllers/debounce_controller.js +14 -0
  18. data/app/javascript/controllers/dropdown_controller.js +38 -0
  19. data/app/javascript/controllers/filter_checkboxes_controller.js +28 -0
  20. data/app/javascript/controllers/index.js +17 -0
  21. data/app/javascript/controllers/search_select_controller.js +30 -0
  22. data/app/jobs/cellscan/application_job.rb +4 -0
  23. data/app/mailers/cellscan/application_mailer.rb +6 -0
  24. data/app/models/cellscan/application_record.rb +5 -0
  25. data/app/views/cellscan/files/open.html.erb +42 -0
  26. data/app/views/cellscan/welcome/index.html.erb +1 -0
  27. data/app/views/layouts/cellscan/application.html.erb +16 -0
  28. data/config/routes.rb +6 -0
  29. data/config/tailwind.config.js +24 -0
  30. data/lib/cellscan/engine.rb +5 -0
  31. data/lib/cellscan/version.rb +3 -0
  32. data/lib/cellscan.rb +6 -0
  33. data/lib/generators/cellscan/base_generator.rb +13 -0
  34. data/lib/generators/cellscan/install_generator.rb +24 -0
  35. data/lib/generators/cellscan/templates/initializer/cellscan.tt +3 -0
  36. data/lib/tasks/cellscan_tasks.rake +4 -0
  37. metadata +152 -0
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/cellscan .css
@@ -0,0 +1,12 @@
1
+
2
+ p.foo {
3
+ text-decoration: dashed;
4
+ }
5
+
6
+ .translation_missing {
7
+ color: red;
8
+ }
9
+ .translation_missing::before {
10
+ content: "⚠️";
11
+ color: red;
12
+ }
@@ -0,0 +1,89 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+
6
+ @layer components {
7
+ .sticky-content {
8
+ @apply sticky top-0 pt-4 bg-white z-20
9
+ }
10
+ .modal {
11
+ @apply w-full md:w-2/3 p-5 bg-slate-300 fixed top-16 md:top-10 md:right-10 rounded-md shadow-md break-words z-30
12
+ }
13
+ .search-input {
14
+ @apply block w-full py-3 px-4 my-4 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500
15
+ }
16
+ }
17
+
18
+
19
+
20
+
21
+ .pagy-nav,
22
+ .pagy-nav-js {
23
+ @apply flex space-x-2;
24
+ }
25
+
26
+ .pagy-nav .page a,
27
+ .pagy-nav .page.active,
28
+ .pagy-nav .page.prev.disabled,
29
+ .pagy-nav .page.next.disabled,
30
+ .pagy-nav-js .page a,
31
+ .pagy-nav-js .page.active,
32
+ .pagy-nav-js .page.prev.disabled,
33
+ .pagy-nav-js .page.next.disabled {
34
+ @apply block rounded-lg px-3 py-1 text-sm text-gray-500 font-semibold bg-gray-200 shadow-md;
35
+ &:hover{
36
+ @apply bg-gray-300;
37
+ }
38
+ &:active{
39
+ @apply bg-gray-400 text-white;
40
+ }
41
+ }
42
+
43
+ .pagy-nav .page.prev.disabled,
44
+ .pagy-nav .page.next.disabled,
45
+ .pagy-nav-js .page.prev.disabled,
46
+ .pagy-nav-js .page.next.disabled {
47
+ @apply text-gray-400 cursor-default;
48
+ &:hover {
49
+ @apply text-gray-400 bg-gray-200;
50
+ }
51
+ &:active {
52
+ @apply text-gray-400 bg-gray-200;
53
+ }
54
+ }
55
+
56
+ .pagy-nav .page.active,
57
+ .pagy-nav-js .page.active {
58
+ @apply text-white cursor-default bg-gray-400;
59
+ &:hover {
60
+ @apply text-white bg-gray-400;
61
+ }
62
+ &:active {
63
+ @apply bg-gray-400 text-white;
64
+ }
65
+ }
66
+
67
+
68
+ .pagy-combo-nav-js {
69
+ @apply flex max-w-max rounded-full px-3 py-1 text-sm text-gray-500 font-semibold bg-gray-200 shadow-md;
70
+ }
71
+
72
+ .pagy-combo-nav-js .pagy-combo-input {
73
+ @apply bg-white px-2 rounded-sm
74
+ }
75
+
76
+ .pagy-combo-nav-js .page.prev,
77
+ .pagy-combo-nav-js .page.next {
78
+ &:hover {
79
+ @apply text-gray-800;
80
+ }
81
+ &:active {
82
+ @apply text-gray-800;
83
+ }
84
+ }
85
+
86
+ .pagy-combo-nav-js .page.prev.disabled,
87
+ .pagy-combo-nav-js .page.next.disabled {
88
+ @apply text-gray-400 cursor-default;
89
+ }
@@ -0,0 +1,6 @@
1
+ module Cellscan
2
+ class ApplicationController < ActionController::Base
3
+ layout 'cellscan/application'
4
+ include Pagy::Backend
5
+ end
6
+ end
@@ -0,0 +1,36 @@
1
+ require "pagy"
2
+ require "pagy/extras/array"
3
+
4
+ module Cellscan
5
+ class FilesController < ApplicationController
6
+ include Pagy::Backend
7
+ include ActionView::Helpers::UrlHelper
8
+
9
+ Pagy::DEFAULT[:items] = 10
10
+
11
+ def open
12
+ @path = params[:path]
13
+ @highlight = params[:highlight]&.to_i
14
+ @error = nil
15
+ if @path.present?
16
+ begin
17
+ @headers, data = Cellscan.file_loader.call(@path)
18
+ data = convert_links(data) if @headers.first == "ZIPCONTENT"
19
+ @headers.unshift("index")
20
+ opts = { page: (@highlight.to_f / Pagy::DEFAULT[:items]).ceil } if @highlight
21
+ data = data.map.with_index { |row, i| [i + 1, *row] }
22
+ @pagy, @rows = pagy_array(data, **opts || {})
23
+ rescue => e
24
+ @error = e.message
25
+ end
26
+ end
27
+ end
28
+
29
+ private def convert_links(data)
30
+ data.map do |row|
31
+ row[1] = link_to("open", open_files_path(path: row[1]), class: "underline")
32
+ row
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,6 @@
1
+ module Cellscan
2
+ class WelcomeController < ActionController::Base
3
+ def index
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Cellscan
2
+ module ApplicationHelper
3
+ include Pagy::Frontend
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
2
+
3
+ import "@hotwired/turbo-rails"
4
+ import "./controllers"
5
+
@@ -0,0 +1,9 @@
1
+ import { Application } from "@hotwired/stimulus"
2
+
3
+ const application = Application.start()
4
+
5
+ // Configure Stimulus development experience
6
+ application.debug = false
7
+ window.Stimulus = application
8
+
9
+ export { application }
@@ -0,0 +1,14 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = [ "form" ]
5
+
6
+ // connect() { console.log("debounce controller connected") }
7
+
8
+ search() {
9
+ clearTimeout(this.timeout)
10
+ this.timeout = setTimeout(() => {
11
+ this.formTarget.requestSubmit()
12
+ }, 500)
13
+ }
14
+ }
@@ -0,0 +1,38 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { useClickOutside } from 'stimulus-use'
3
+
4
+ export default class extends Controller {
5
+ static targets = ['dropdown', 'icon', 'button']
6
+
7
+ connect() {
8
+ this.iconTarget.classList.add('rotate-180');
9
+ this.dropdownTarget.classList.add('hidden');
10
+
11
+ useClickOutside(this, { element: this.dropdownTarget });
12
+ }
13
+
14
+
15
+ clickOutside(event) {
16
+ // We are outside the dropdown, but still hit the button.
17
+ // Then we DONT want to close the dropdown -
18
+ // else the toggle would come on top an dopen it again.
19
+ if (this.buttonTarget.contains(event.target)) {
20
+ return
21
+ }
22
+ event.preventDefault()
23
+ this.closeDrowdown()
24
+ }
25
+
26
+ toggle() {
27
+ this.dropdownTarget.classList.toggle('hidden')
28
+
29
+ this.iconTarget.classList.toggle('rotate-180');
30
+ this.iconTarget.classList.toggle('rotate-0');
31
+ }
32
+
33
+ closeDrowdown() {
34
+ this.iconTarget.classList.add('rotate-180');
35
+ this.dropdownTarget.classList.add('hidden')
36
+ }
37
+
38
+ }
@@ -0,0 +1,28 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ const selectedValues = this.element.dataset.selectedValues
6
+ // const selectedValues = JSON.parse(this.element.dataset.selectedValues)
7
+ const checkboxes = this.element.querySelectorAll("input[type=checkbox]")
8
+
9
+ checkboxes.forEach((checkbox) => {
10
+ if (selectedValues.includes(checkbox.value)) {
11
+ checkbox.checked = true
12
+ } else {
13
+ checkbox.checked = false
14
+ }
15
+ })
16
+ }
17
+
18
+ // We can do this later
19
+ // data-action="click->filter-checkboxes#toggleCheckbox" data-checkbox-id="<%=tag%>"
20
+ toggleCheckbox(event) {
21
+ const checkboxId = event.currentTarget.dataset.checkboxId
22
+ const checkbox = this.element.querySelector(`input[type='checkbox'][value='${checkboxId}']`);
23
+ if (checkbox) {
24
+ checkbox.checked = !checkbox.checked
25
+ }
26
+ }
27
+
28
+ }
@@ -0,0 +1,17 @@
1
+ // This file is auto-generated by ./bin/rails stimulus:manifest:update
2
+ // Run that command whenever you add a new controller or create them with
3
+ // ./bin/rails generate stimulus controllerName
4
+
5
+ import { application } from "./application"
6
+
7
+ import DebounceController from "./debounce_controller"
8
+ application.register("debounce", DebounceController)
9
+
10
+ import FilterCheckboxesController from "./filter_checkboxes_controller"
11
+ application.register("filter-checkboxes", FilterCheckboxesController)
12
+
13
+ import DropdownController from "./dropdown_controller"
14
+ application.register("dropdown", DropdownController)
15
+
16
+ import SearchSelectController from "./search_select_controller"
17
+ application.register("search-select", SearchSelectController)
@@ -0,0 +1,30 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["id", "input", "dropdown", "item"];
5
+
6
+ connect() {
7
+ this.inputTarget.focus();
8
+ }
9
+
10
+ search() {
11
+ const searchTerm = this.inputTarget.value.trim().toLowerCase();
12
+ let found = false;
13
+ this.itemTargets.forEach((element) => {
14
+ const text = element.textContent.trim().toLowerCase();
15
+ element.hidden = !text.includes(searchTerm);
16
+ if (text.includes(searchTerm)) {
17
+ found = true;
18
+ }
19
+ });
20
+ this.dropdownTarget.classList.remove("hidden");
21
+ }
22
+
23
+ select(event) {
24
+ const element = event.currentTarget;
25
+ this.inputTarget.value = element.textContent.trim();
26
+ this.dropdownTarget.classList.add("hidden");
27
+
28
+ this.idTarget.value = event.currentTarget.dataset.personId;
29
+ }
30
+ }
@@ -0,0 +1,4 @@
1
+ module Cellscan
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Cellscan
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Cellscan
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,42 @@
1
+ <% if @rows %>
2
+ <div class="overflow-x-auto">
3
+ <table class="min-w-full table-auto">
4
+ <thead>
5
+ <tr class="bg-gray-800 text-white">
6
+ <% @headers.each do |header| %>
7
+ <th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
8
+ <%= header %>
9
+ </th>
10
+ <% end %>
11
+ </tr>
12
+ </thead>
13
+ <tbody class="bg-white divide-y divide-gray-200">
14
+ <% @rows.each_with_index do |row, index| %>
15
+ <% bg = index.odd? ? 'bg-gray-50' : 'bg-white' %>
16
+ <% bg = 'bg-yellow-100' if row.first == @highlight %>
17
+ <tr class="<%= bg %>">
18
+ <% row.each do |field| %>
19
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
20
+ <%= field %>
21
+ </td>
22
+ <% end %>
23
+ </tr>
24
+ <% end %>
25
+ </tbody>
26
+ </table>
27
+ </div>
28
+
29
+ <div class="my-6">
30
+ <%== pagy_nav(@pagy) %>
31
+ </div>
32
+ <% else %>
33
+ Could not read file <b><%= @path %></b>
34
+ <hr />
35
+ I'm mounted under <%= Rails.root %>
36
+
37
+ <% if @error %>
38
+ <hr />
39
+ <pre><%= @error %></pre>
40
+ <% end %>
41
+
42
+ <% end %>
@@ -0,0 +1 @@
1
+ Welcome to Cell scan
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Cell scan</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+ <%= action_cable_meta_tag %>
8
+ <%= stylesheet_link_tag "cellscan/application", "data-turbo-track": "reload" %>
9
+ <%= javascript_include_tag 'cellscan/application', 'data-turbo-track': 'reload', defer: false %>
10
+ </head>
11
+ <body>
12
+
13
+ <%= yield %>
14
+
15
+ </body>
16
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ Cellscan::Engine.routes.draw do
2
+ resources :files do
3
+ get :open, on: :collection
4
+ end
5
+ root to: 'welcome#index'
6
+ end
@@ -0,0 +1,24 @@
1
+ const defaultTheme = require('tailwindcss/defaultTheme')
2
+
3
+ module.exports = {
4
+ content: [
5
+ './app/views/**/*.rb',
6
+ './public/*.html',
7
+ './app/helpers/**/*.rb',
8
+ './app/javascript/**/*.js',
9
+ './app/views/**/*.erb',
10
+ './app/components/**/*.erb'
11
+ ],
12
+ theme: {
13
+ extend: {
14
+ fontFamily: {
15
+ sans: ['Inter var', ...defaultTheme.fontFamily.sans],
16
+ },
17
+ },
18
+ },
19
+ plugins: [
20
+ require('@tailwindcss/forms'),
21
+ require('@tailwindcss/aspect-ratio'),
22
+ require('@tailwindcss/typography'),
23
+ ]
24
+ }
@@ -0,0 +1,5 @@
1
+ module Cellscan
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Cellscan
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Cellscan
2
+ VERSION = "0.1.0"
3
+ end
data/lib/cellscan.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "cellscan/version"
2
+ require "cellscan/engine"
3
+
4
+ module Cellscan
5
+ mattr_accessor :file_loader
6
+ end
@@ -0,0 +1,13 @@
1
+ require "rails/generators"
2
+
3
+ module Generators
4
+ module Avo
5
+ class BaseGenerator < ::Rails::Generators::Base
6
+ hide!
7
+
8
+ def initialize(*args)
9
+ super(*args)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ require_relative "base_generator"
2
+
3
+ module Generators
4
+ module Cellscan
5
+ class InstallGenerator < BaseGenerator
6
+ namespace "cellscan:install"
7
+ desc "Creates a Cellscan initializer adds the route to the routes file."
8
+ class_option :path, type: :string, default: "cellscan"
9
+
10
+ def create_initializer_file
11
+ route "mount Cellscan::Engine, at: '/cellscan'"
12
+
13
+ template "initializer/avo.tt", "config/initializers/cellscan.rb"
14
+ directory File.join(__dir__, "templates", "locales"), "config/locales"
15
+ end
16
+
17
+ unless Rails.root.join("app", "assets", "stylesheets", "cellscan.tailwind.css").exist?
18
+ say "Add default app/assets/stylesheets/cellscan.tailwind.css"
19
+ copy_file template_path("tailwind.css"), "app/assets/stylesheets/cellscan.tailwind.css"
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ Cellscan.configure do |config|
2
+
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :cellscan do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cellscan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Till Carlos
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-04-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tailwindcss-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: stimulus-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pagy
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '6.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '6.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubyzip
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ description: Include the engine in your Rails app and you can view CSV files in your
84
+ browser.
85
+ email:
86
+ - till@tillcarlos.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - MIT-LICENSE
92
+ - README.md
93
+ - Rakefile
94
+ - app/assets/builds/cellscan/application.css
95
+ - app/assets/builds/cellscan/application.js
96
+ - app/assets/builds/cellscan/application.js.map
97
+ - app/assets/config/cellscan_manifest.js
98
+ - app/assets/stylesheets/cellscan/application.css
99
+ - app/assets/stylesheets/cellscan/application.tailwind.css
100
+ - app/controllers/cellscan/application_controller.rb
101
+ - app/controllers/cellscan/files_controller.rb
102
+ - app/controllers/cellscan/welcome_controller.rb
103
+ - app/helpers/cellscan/application_helper.rb
104
+ - app/javascript/application.js
105
+ - app/javascript/controllers/application.js
106
+ - app/javascript/controllers/debounce_controller.js
107
+ - app/javascript/controllers/dropdown_controller.js
108
+ - app/javascript/controllers/filter_checkboxes_controller.js
109
+ - app/javascript/controllers/index.js
110
+ - app/javascript/controllers/search_select_controller.js
111
+ - app/jobs/cellscan/application_job.rb
112
+ - app/mailers/cellscan/application_mailer.rb
113
+ - app/models/cellscan/application_record.rb
114
+ - app/views/cellscan/files/open.html.erb
115
+ - app/views/cellscan/welcome/index.html.erb
116
+ - app/views/layouts/cellscan/application.html.erb
117
+ - config/routes.rb
118
+ - config/tailwind.config.js
119
+ - lib/cellscan.rb
120
+ - lib/cellscan/engine.rb
121
+ - lib/cellscan/version.rb
122
+ - lib/generators/cellscan/base_generator.rb
123
+ - lib/generators/cellscan/install_generator.rb
124
+ - lib/generators/cellscan/templates/initializer/cellscan.tt
125
+ - lib/tasks/cellscan_tasks.rake
126
+ homepage: https://tillcarlos.com/cellscan
127
+ licenses:
128
+ - MIT
129
+ metadata:
130
+ homepage_uri: https://tillcarlos.com/cellscan
131
+ source_code_uri: https://tillcarlos.com/cellscan
132
+ changelog_uri: https://tillcarlos.com/cellscan
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubygems_version: 3.2.32
149
+ signing_key:
150
+ specification_version: 4
151
+ summary: A simple CSV viewer as an engine for Rails.
152
+ test_files: []