solidstats 0.0.2 → 0.0.3
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 +4 -4
- data/CHANGELOG.md +35 -0
- data/README.md +15 -2
- data/app/controllers/solidstats/dashboard_controller.rb +84 -1
- data/app/views/solidstats/dashboard/_todos.html.erb +172 -0
- data/app/views/solidstats/dashboard/index.html.erb +2 -0
- data/lib/generators/solidstats/install/install_generator.rb +32 -0
- data/lib/generators/solidstats/install/templates/README +18 -0
- data/lib/solidstats/engine.rb +6 -1
- data/lib/solidstats/version.rb +1 -1
- data/lib/solidstats.rb +13 -1
- data/lib/tasks/solidstats_install.rake +13 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f752538540fc6711f9cb874ee24b1a5fd64986c7fc306b6019994567993a2213
|
4
|
+
data.tar.gz: db591225a673fd6d863b31402d2e212b6669f93ff90e7daea9016dd9f2729f1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 324af0252248b56a47b09ac4211c33c8547d28dec98d9458077cccf736742c31ff09b5bff70fcb2d1754e7ff5a0e6c00c12a832e9406031af7fc0f5665557f8d
|
7
|
+
data.tar.gz: b49c025af721bb4f2bd6ddc15857f6f6a46827e223bb8b23d1f6a9641e5ba7848a75b6778854636f2008f2c38f0d7bb94c1adbc6248a7cb0117a81b6d9134708
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [0.0.3] - 2025-05-20
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Install generator (`rails g solidstats:install`) to automatically mount routes
|
12
|
+
- Rake task (`rake solidstats:install`) as an alias for the generator
|
13
|
+
- Improved documentation for installation process
|
14
|
+
|
15
|
+
## [0.0.2] - 2025-05-19
|
16
|
+
|
17
|
+
### Added
|
18
|
+
- Asset precompilation configuration for solidstats/application.css in development environment
|
19
|
+
|
20
|
+
## [0.0.1] - 2025-05-19
|
21
|
+
|
22
|
+
### Added
|
23
|
+
- Initial release of the Solidstats gem
|
24
|
+
- Basic engine structure
|
25
|
+
- Development mode restriction
|
26
|
+
- Dashboard controller with initial views
|
27
|
+
- Security audit components and views
|
28
|
+
|
29
|
+
## [Unreleased]
|
30
|
+
|
31
|
+
- Improved TODO dashboard partial:
|
32
|
+
- Ensured correct handling of nil keys in the hotspots hash.
|
33
|
+
- Displayed TODO, FIXME, and HACK counts with color-coded badges.
|
34
|
+
- Added expandable details for files with most TODOs and all TODO items.
|
35
|
+
- Enhanced UI with better grouping and error handling for TODO data.
|
data/README.md
CHANGED
@@ -12,13 +12,26 @@ Solidstats is a local-only Rails engine that shows your project's health at `/so
|
|
12
12
|
```ruby
|
13
13
|
# Gemfile (dev only)
|
14
14
|
group :development do
|
15
|
-
gem 'solidstats'
|
15
|
+
gem 'solidstats'
|
16
16
|
end
|
17
17
|
```
|
18
18
|
|
19
|
-
|
19
|
+
After bundle install, you can run the installer:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
bundle exec rails g solidstats:install
|
23
|
+
```
|
24
|
+
|
25
|
+
Or using the provided rake task:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
bundle exec rake solidstats:install
|
29
|
+
```
|
30
|
+
|
31
|
+
The installer will automatically mount the engine in your routes:
|
20
32
|
|
21
33
|
```ruby
|
34
|
+
# config/routes.rb
|
22
35
|
mount Solidstats::Engine => '/solidstats' if Rails.env.development?
|
23
36
|
```
|
24
37
|
|
@@ -1,12 +1,14 @@
|
|
1
1
|
module Solidstats
|
2
2
|
class DashboardController < ApplicationController
|
3
3
|
AUDIT_CACHE_FILE = Rails.root.join("tmp", "solidstats_audit.json")
|
4
|
+
TODO_CACHE_FILE = Rails.root.join("tmp", "solidstats_todos.json")
|
4
5
|
AUDIT_CACHE_HOURS = 12 # Configure how many hours before refreshing
|
5
6
|
|
6
7
|
def index
|
7
8
|
@audit_output = fetch_audit_output
|
8
9
|
@rubocop_output = "JSON.parse(`rubocop --format json`)"
|
9
|
-
@
|
10
|
+
@todo_items = fetch_todo_items
|
11
|
+
@todo_stats = calculate_todo_stats(@todo_items)
|
10
12
|
@coverage = "read_coverage_percent"
|
11
13
|
end
|
12
14
|
|
@@ -44,6 +46,87 @@ module Solidstats
|
|
44
46
|
audit_output
|
45
47
|
end
|
46
48
|
|
49
|
+
def fetch_todo_items
|
50
|
+
# Check if cache file exists and is recent enough
|
51
|
+
if File.exist?(TODO_CACHE_FILE)
|
52
|
+
cached_data = JSON.parse(File.read(TODO_CACHE_FILE))
|
53
|
+
last_run_time = Time.parse(cached_data["timestamp"])
|
54
|
+
|
55
|
+
# Use cached data if it's less than AUDIT_CACHE_HOURS old
|
56
|
+
if Time.now - last_run_time < AUDIT_CACHE_HOURS.hours
|
57
|
+
return cached_data["output"]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
todos = []
|
62
|
+
# Updated grep pattern to match only all-uppercase or all-lowercase variants
|
63
|
+
raw_output = `grep -r -n -E "(TODO|FIXME|HACK|todo|fixme|hack)" app lib`.split("\n")
|
64
|
+
|
65
|
+
raw_output.each do |line|
|
66
|
+
if line =~ /^(.+):(\d+):(.+)$/
|
67
|
+
file = $1
|
68
|
+
line_num = $2
|
69
|
+
content = $3
|
70
|
+
|
71
|
+
# Match only exact lowercase or uppercase variants
|
72
|
+
type_match = content.match(/(TODO|FIXME|HACK|todo|fixme|hack)/)
|
73
|
+
if type_match
|
74
|
+
# Convert to uppercase for consistency
|
75
|
+
type = type_match.to_s.upcase
|
76
|
+
|
77
|
+
todos << {
|
78
|
+
file: file,
|
79
|
+
line: line_num.to_i,
|
80
|
+
content: content.strip,
|
81
|
+
type: type
|
82
|
+
}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Save to cache file with timestamp
|
88
|
+
cache_data = {
|
89
|
+
"output" => todos,
|
90
|
+
"timestamp" => Time.now.iso8601
|
91
|
+
}
|
92
|
+
|
93
|
+
# Ensure the tmp directory exists
|
94
|
+
FileUtils.mkdir_p(File.dirname(TODO_CACHE_FILE))
|
95
|
+
|
96
|
+
# Write the cache file
|
97
|
+
File.write(TODO_CACHE_FILE, JSON.generate(cache_data))
|
98
|
+
|
99
|
+
todos
|
100
|
+
end
|
101
|
+
|
102
|
+
def calculate_todo_stats(todos)
|
103
|
+
return {} if todos.nil? || todos.empty?
|
104
|
+
|
105
|
+
stats = {
|
106
|
+
total: todos.count,
|
107
|
+
by_type: {
|
108
|
+
"TODO" => todos.count { |t| t[:type] == "TODO" },
|
109
|
+
"FIXME" => todos.count { |t| t[:type] == "FIXME" },
|
110
|
+
"HACK" => todos.count { |t| t[:type] == "HACK" }
|
111
|
+
},
|
112
|
+
by_file: {}
|
113
|
+
}
|
114
|
+
|
115
|
+
# Group by file path
|
116
|
+
todos.each do |todo|
|
117
|
+
file_path = todo[:file]
|
118
|
+
stats[:by_file][file_path] ||= 0
|
119
|
+
stats[:by_file][file_path] += 1
|
120
|
+
end
|
121
|
+
|
122
|
+
# Find files with most TODOs (top 5)
|
123
|
+
stats[:hotspots] = stats[:by_file].sort_by { |_, count| -count }
|
124
|
+
.first(5)
|
125
|
+
.to_h
|
126
|
+
|
127
|
+
stats
|
128
|
+
end
|
129
|
+
|
47
130
|
def read_coverage_percent
|
48
131
|
file = Rails.root.join("coverage", ".last_run.json")
|
49
132
|
return 0 unless File.exist?(file)
|
@@ -0,0 +1,172 @@
|
|
1
|
+
<div class="stat-card todo-card">
|
2
|
+
<h2><span class="icon">📝</span> TODO Items</h2>
|
3
|
+
<div class="card-content">
|
4
|
+
<% if @todo_items.nil? %>
|
5
|
+
<div class="status-badge danger">Error loading TODO data</div>
|
6
|
+
<% elsif @todo_items.empty? %>
|
7
|
+
<div class="status-badge success">All Clear</div>
|
8
|
+
<% else %>
|
9
|
+
<div class="status-badge warning"><%= @todo_items.count %> <%= "Item".pluralize(@todo_items.count) %> Found</div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<% if @todo_items.present? && @todo_stats.present? %>
|
13
|
+
<%
|
14
|
+
# Ensure we have proper counts by type - recalculate if needed
|
15
|
+
todo_count = @todo_items.count { |item| (item[:type] || item["type"])&.upcase == "TODO" }
|
16
|
+
fixme_count = @todo_items.count { |item| (item[:type] || item["type"])&.upcase == "FIXME" }
|
17
|
+
hack_count = @todo_items.count { |item| (item[:type] || item["type"])&.upcase == "HACK" }
|
18
|
+
%>
|
19
|
+
<div class="metrics-group">
|
20
|
+
<div class="metric">
|
21
|
+
<span class="metric-label">TODO:</span>
|
22
|
+
<span class="metric-value"><%= todo_count %></span>
|
23
|
+
</div>
|
24
|
+
<div class="metric">
|
25
|
+
<span class="metric-label">FIXME:</span>
|
26
|
+
<span class="metric-value text-danger"><%= fixme_count %></span>
|
27
|
+
</div>
|
28
|
+
<div class="metric">
|
29
|
+
<span class="metric-label">HACK:</span>
|
30
|
+
<span class="metric-value text-warning"><%= hack_count %></span>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<a href="#" class="toggle-details" data-target="todo-details">Show Details</a>
|
35
|
+
<% end %>
|
36
|
+
</div>
|
37
|
+
|
38
|
+
<% if @todo_items.present? && @todo_stats.present? %>
|
39
|
+
<div id="todo-details" class="details-panel hidden">
|
40
|
+
<h3 class="details-section-title">Files with Most TODOs</h3>
|
41
|
+
<div class="table-responsive mb-4">
|
42
|
+
<table class="table">
|
43
|
+
<thead>
|
44
|
+
<tr>
|
45
|
+
<th>File</th>
|
46
|
+
<th class="text-end">Count</th>
|
47
|
+
</tr>
|
48
|
+
</thead>
|
49
|
+
<tbody>
|
50
|
+
<%
|
51
|
+
# If hotspots has nil keys, reconstruct it from @todo_items
|
52
|
+
hotspots = @todo_stats[:hotspots]
|
53
|
+
if hotspots.is_a?(Hash) && hotspots.keys.any?(&:nil?)
|
54
|
+
# Rebuild hotspots from todo_items
|
55
|
+
hotspots = {}
|
56
|
+
@todo_items.each do |item|
|
57
|
+
item_hash = item.respond_to?(:symbolize_keys) ? item.symbolize_keys : item
|
58
|
+
file = item_hash[:file] || item["file"]
|
59
|
+
next unless file.present?
|
60
|
+
hotspots[file] ||= 0
|
61
|
+
hotspots[file] += 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
%>
|
65
|
+
|
66
|
+
<% if hotspots.present? %>
|
67
|
+
<% hotspots.each do |file, count| %>
|
68
|
+
<tr>
|
69
|
+
<td><code><%= file.nil? ? "Unknown File" : file.to_s %></code></td>
|
70
|
+
<td class="text-end"><%= count.to_i %></td>
|
71
|
+
</tr>
|
72
|
+
<% end %>
|
73
|
+
<% else %>
|
74
|
+
<tr>
|
75
|
+
<td colspan="2">No hotspot data available</td>
|
76
|
+
</tr>
|
77
|
+
<% end %>
|
78
|
+
</tbody>
|
79
|
+
</table>
|
80
|
+
</div>
|
81
|
+
|
82
|
+
<h3 class="details-section-title">All TODO Items</h3>
|
83
|
+
<div class="accordion" id="todoAccordion">
|
84
|
+
<% @todo_items.each_with_index do |item, index| %>
|
85
|
+
<%
|
86
|
+
# Convert item to a hash with symbol keys if it's a hash with string keys
|
87
|
+
item = item.symbolize_keys if item.respond_to?(:symbolize_keys)
|
88
|
+
%>
|
89
|
+
<div class="accordion-item">
|
90
|
+
<h4 class="accordion-header">
|
91
|
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#todo-<%= index %>">
|
92
|
+
<span class="badge <%= item[:type] == 'FIXME' ? 'bg-danger' : (item[:type] == 'HACK' ? 'bg-warning' : 'bg-primary') %> me-2"><%= item[:type] || "TODO" %></span>
|
93
|
+
<%= File.basename(item[:file].to_s) %>:<%= item[:line] || '?' %>
|
94
|
+
</button>
|
95
|
+
</h4>
|
96
|
+
<div id="todo-<%= index %>" class="accordion-collapse collapse" data-bs-parent="#todoAccordion">
|
97
|
+
<div class="accordion-body">
|
98
|
+
<p><code class="d-block"><%= item[:content].to_s %></code></p>
|
99
|
+
<small class="text-muted">File: <%= item[:file].to_s %></small>
|
100
|
+
</div>
|
101
|
+
</div>
|
102
|
+
</div>
|
103
|
+
<% end %>
|
104
|
+
</div>
|
105
|
+
</div>
|
106
|
+
<% end %>
|
107
|
+
</div>
|
108
|
+
|
109
|
+
<style>
|
110
|
+
/* Additional styles for todo card */
|
111
|
+
.todo-card.expanded {
|
112
|
+
grid-column: 1 / -1;
|
113
|
+
width: 100%;
|
114
|
+
}
|
115
|
+
|
116
|
+
.details-section-title {
|
117
|
+
font-size: 1.1rem;
|
118
|
+
font-weight: 600;
|
119
|
+
margin: 1.5rem 0 1rem 0;
|
120
|
+
}
|
121
|
+
|
122
|
+
.details-section-title:first-child {
|
123
|
+
margin-top: 0;
|
124
|
+
}
|
125
|
+
|
126
|
+
/* Fix for accordion within the card */
|
127
|
+
.todo-card .accordion {
|
128
|
+
margin-top: 1rem;
|
129
|
+
}
|
130
|
+
|
131
|
+
.todo-card .accordion-item {
|
132
|
+
border: 1px solid rgba(0, 0, 0, 0.125);
|
133
|
+
margin-bottom: 0.5rem;
|
134
|
+
border-radius: 4px;
|
135
|
+
overflow: hidden;
|
136
|
+
}
|
137
|
+
|
138
|
+
.todo-card .accordion-button {
|
139
|
+
padding: 0.75rem 1rem;
|
140
|
+
font-size: 0.9rem;
|
141
|
+
background-color: #f8f9fa;
|
142
|
+
}
|
143
|
+
|
144
|
+
.todo-card .accordion-button:not(.collapsed) {
|
145
|
+
background-color: #e7f1ff;
|
146
|
+
}
|
147
|
+
|
148
|
+
.todo-card .accordion-body {
|
149
|
+
padding: 1rem;
|
150
|
+
background-color: #fff;
|
151
|
+
}
|
152
|
+
|
153
|
+
.todo-card code {
|
154
|
+
font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
155
|
+
font-size: 0.85rem;
|
156
|
+
padding: 0.2rem 0.4rem;
|
157
|
+
background: #f6f8fa;
|
158
|
+
border-radius: 3px;
|
159
|
+
color: #24292e;
|
160
|
+
}
|
161
|
+
|
162
|
+
.todo-card code.d-block {
|
163
|
+
display: block;
|
164
|
+
padding: 0.75rem;
|
165
|
+
margin-bottom: 0.5rem;
|
166
|
+
white-space: pre-wrap;
|
167
|
+
word-break: break-word;
|
168
|
+
background: #f6f8fa;
|
169
|
+
border-radius: 4px;
|
170
|
+
border: 1px solid #e1e4e8;
|
171
|
+
}
|
172
|
+
</style>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
|
3
|
+
module Solidstats
|
4
|
+
module Generators
|
5
|
+
# This generator installs Solidstats routes in the host application
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# $ rails generate solidstats:install
|
9
|
+
#
|
10
|
+
# This will:
|
11
|
+
# 1. Add the Solidstats routes to the host application's config/routes.rb
|
12
|
+
# 2. Show a helpful README with next steps
|
13
|
+
class InstallGenerator < Rails::Generators::Base
|
14
|
+
source_root File.expand_path("templates", __dir__)
|
15
|
+
desc "Adds Solidstats routes to your development application"
|
16
|
+
|
17
|
+
def add_routes
|
18
|
+
route_code = <<-RUBY
|
19
|
+
# Solidstats Routes (development only)
|
20
|
+
mount Solidstats::Engine => "/solidstats" if Rails.env.development?
|
21
|
+
RUBY
|
22
|
+
|
23
|
+
route route_code
|
24
|
+
say_status :routes, "Mounting Solidstats engine at /solidstats (development environment only)", :green
|
25
|
+
end
|
26
|
+
|
27
|
+
def show_readme
|
28
|
+
readme "README" if behavior == :invoke
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
===============================================================================
|
2
|
+
|
3
|
+
Solidstats has been successfully installed for development!
|
4
|
+
|
5
|
+
Your Solidstats dashboard is now available at: /solidstats
|
6
|
+
(Only in development environment)
|
7
|
+
|
8
|
+
To access your stats:
|
9
|
+
1. Start your Rails server: bundle exec rails s
|
10
|
+
2. Visit: http://localhost:3000/solidstats
|
11
|
+
|
12
|
+
Solidstats will show you:
|
13
|
+
- TODO/FIXME items in your codebase
|
14
|
+
- Security audit information
|
15
|
+
- Code quality metrics
|
16
|
+
- And more!
|
17
|
+
|
18
|
+
===============================================================================
|
data/lib/solidstats/engine.rb
CHANGED
@@ -10,8 +10,13 @@ module Solidstats
|
|
10
10
|
|
11
11
|
initializer "solidstats.assets.precompile" do |app|
|
12
12
|
if Rails.env.development?
|
13
|
-
app.config.assets.precompile += %w
|
13
|
+
app.config.assets.precompile += %w[ solidstats/application.css ]
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
# Load the solidstats rake tasks
|
18
|
+
rake_tasks do
|
19
|
+
Dir[File.join(File.dirname(__FILE__), "../tasks/**/*.rake")].each { |f| load f }
|
20
|
+
end
|
16
21
|
end
|
17
22
|
end
|
data/lib/solidstats/version.rb
CHANGED
data/lib/solidstats.rb
CHANGED
@@ -2,5 +2,17 @@ require "solidstats/version"
|
|
2
2
|
require "solidstats/engine"
|
3
3
|
|
4
4
|
module Solidstats
|
5
|
-
|
5
|
+
class << self
|
6
|
+
# Returns the absolute path to this gem's root directory
|
7
|
+
# @return [String] Gem root path
|
8
|
+
def root
|
9
|
+
File.dirname(__dir__)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns version string
|
13
|
+
# @return [String] Version
|
14
|
+
def version
|
15
|
+
VERSION
|
16
|
+
end
|
17
|
+
end
|
6
18
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
namespace :solidstats do
|
3
|
+
desc "Install Solidstats into your Rails application"
|
4
|
+
task :install do
|
5
|
+
if system "rails g solidstats:install"
|
6
|
+
puts "\n✅ Solidstats installation completed successfully!"
|
7
|
+
puts " Start your Rails server and visit http://localhost:3000/solidstats\n\n"
|
8
|
+
else
|
9
|
+
puts "\n❌ Solidstats installation failed. Please try running manually:"
|
10
|
+
puts " bundle exec rails generate solidstats:install\n\n"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solidstats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MezbahAlam
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -45,6 +45,7 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- CHANGELOG.md
|
48
49
|
- MIT-LICENSE
|
49
50
|
- README.md
|
50
51
|
- Rakefile
|
@@ -56,6 +57,7 @@ files:
|
|
56
57
|
- app/mailers/solidstats/application_mailer.rb
|
57
58
|
- app/models/solidstats/application_record.rb
|
58
59
|
- app/views/layouts/solidstats/application.html.erb
|
60
|
+
- app/views/solidstats/dashboard/_todos.html.erb
|
59
61
|
- app/views/solidstats/dashboard/audit/_audit_badge.html.erb
|
60
62
|
- app/views/solidstats/dashboard/audit/_audit_details.html.erb
|
61
63
|
- app/views/solidstats/dashboard/audit/_audit_filters.html.erb
|
@@ -66,9 +68,12 @@ files:
|
|
66
68
|
- app/views/solidstats/dashboard/audit/_vulnerability_details.html.erb
|
67
69
|
- app/views/solidstats/dashboard/index.html.erb
|
68
70
|
- config/routes.rb
|
71
|
+
- lib/generators/solidstats/install/install_generator.rb
|
72
|
+
- lib/generators/solidstats/install/templates/README
|
69
73
|
- lib/solidstats.rb
|
70
74
|
- lib/solidstats/engine.rb
|
71
75
|
- lib/solidstats/version.rb
|
76
|
+
- lib/tasks/solidstats_install.rake
|
72
77
|
- lib/tasks/solidstats_tasks.rake
|
73
78
|
homepage: https://solidstats.infolily.com
|
74
79
|
licenses:
|