broken_window 1.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 (39) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +45 -0
  4. data/Rakefile +21 -0
  5. data/app/assets/javascripts/broken_window/application.js +13 -0
  6. data/app/assets/stylesheets/broken_window/application.scss +25 -0
  7. data/app/assets/stylesheets/broken_window/layout.sass +39 -0
  8. data/app/assets/stylesheets/broken_window/metric.sass +16 -0
  9. data/app/assets/stylesheets/broken_window/metrics_list.sass +38 -0
  10. data/app/controllers/broken_window/application_controller.rb +4 -0
  11. data/app/controllers/broken_window/metrics_controller.rb +48 -0
  12. data/app/helpers/broken_window/application_helper.rb +4 -0
  13. data/app/models/broken_window/measured_metric.rb +54 -0
  14. data/app/models/broken_window/measurement.rb +7 -0
  15. data/app/models/broken_window/metric.rb +40 -0
  16. data/app/models/broken_window/metric_status.rb +37 -0
  17. data/app/services/broken_window/formatters/integer.rb +11 -0
  18. data/app/services/broken_window/formatters/percentage.rb +11 -0
  19. data/app/services/broken_window/measurer.rb +11 -0
  20. data/app/services/broken_window/metric_measurer.rb +26 -0
  21. data/app/services/broken_window/service.rb +23 -0
  22. data/app/services/broken_window/status_checker.rb +37 -0
  23. data/app/views/broken_window/metrics/_error_messages.html.erb +10 -0
  24. data/app/views/broken_window/metrics/_form.html.erb +35 -0
  25. data/app/views/broken_window/metrics/_list.html.erb +13 -0
  26. data/app/views/broken_window/metrics/edit.html.erb +5 -0
  27. data/app/views/broken_window/metrics/index.html.erb +4 -0
  28. data/app/views/broken_window/metrics/new.html.erb +5 -0
  29. data/app/views/broken_window/metrics/show.html.erb +17 -0
  30. data/app/views/layouts/broken_window/application.html.erb +16 -0
  31. data/config/routes.rb +4 -0
  32. data/db/migrate/20160112005320_create_broken_window_metrics.rb +13 -0
  33. data/db/migrate/20160112010703_create_broken_window_measurements.rb +9 -0
  34. data/db/migrate/20160419161925_add_parent_id_to_metrics.rb +5 -0
  35. data/lib/broken_window/engine.rb +5 -0
  36. data/lib/broken_window/version.rb +3 -0
  37. data/lib/broken_window.rb +14 -0
  38. data/lib/tasks/broken_window_tasks.rake +7 -0
  39. metadata +151 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4f486568923c0240a670406f6f39d43106de773f
4
+ data.tar.gz: c8bc0696766613a6c62aca487087c928e3eb8855
5
+ SHA512:
6
+ metadata.gz: 62b0209d894eb0d4108689842ac8386673f4905f1f91037b476bb50f092be9b79255c18c4f15704f25df4dea5c87031e6532a24d084bd3143e2adc17533c60e5
7
+ data.tar.gz: 7a846fb8f52c16f81cb0ff83738bfd93d638af2de767e2ba50b2e1c6f1e95b9e85e050067763e4f93d0471ecadb0947589b33e767ef5935c9ea318b4bb5c6850
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 YOURNAME
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.rdoc ADDED
@@ -0,0 +1,45 @@
1
+ = BrokenWindow
2
+
3
+ This project rocks and uses MIT-LICENSE.
4
+
5
+ Installation
6
+ =============
7
+
8
+ Add:
9
+
10
+ gem 'broken_window', github: 'webpunch/broken_window'
11
+
12
+ to your Gemfile
13
+
14
+ Run: rake broken_window:install:migrations && rake db:migrate
15
+
16
+ Add to your routes file:
17
+
18
+ mount BrokenWindow::Engine => "/status"
19
+
20
+ Create config/initializers/broken_window.rb to register your calculators:
21
+
22
+ BrokenWindow.register_calculators [
23
+ BrokenWindow::Calculators::ExampleCalculator
24
+ ]
25
+
26
+ Create your calculator:
27
+
28
+
29
+ module BrokenWindow
30
+ module Calculators
31
+ class ExampleCalculator
32
+ def initialize(options = {})
33
+
34
+ end
35
+
36
+ def call
37
+ # Thing to be calculated
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+
44
+
45
+
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'BrokenWindow'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,25 @@
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 vendor/assets/stylesheets of plugins, if any, 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 styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *=
14
+ */
15
+
16
+ @mixin clearfix {
17
+ &:after {
18
+ content: "";
19
+ display: table;
20
+ clear: both;
21
+ }
22
+ }
23
+
24
+ @import "./*.sass"
25
+
@@ -0,0 +1,39 @@
1
+ a.back-link
2
+ float: left
3
+ text-decoration: none
4
+ color: black
5
+ font-size: 42px
6
+
7
+ .page-actions
8
+ text-align: center
9
+
10
+ a
11
+ color: black
12
+ font-size: 42px
13
+ text-decoration: none
14
+
15
+ .error_explanation
16
+ color: red
17
+
18
+ body
19
+ color: black
20
+ padding: 10px
21
+
22
+ &.fail
23
+ background-color: red
24
+
25
+ &.pass
26
+ background-color: green
27
+
28
+ &.unknown
29
+ background-color: gray
30
+
31
+ &.background-metric
32
+ &.fail
33
+ background-color: darken(red, 10%)
34
+
35
+ &.pass
36
+ background-color: darken(green, 10%)
37
+
38
+ &.unknown
39
+ background-color: darken(gray, 10%)
@@ -0,0 +1,16 @@
1
+ .show-metric
2
+ padding-top: 3em
3
+ padding-bottom: 3em
4
+ text-align: center
5
+
6
+ h1
7
+ font-size: 52px
8
+ max-width: 700px
9
+ margin-left: auto
10
+ margin-right: auto
11
+
12
+ .value
13
+ font-size: 80px
14
+
15
+ .required
16
+ font-size: 24px
@@ -0,0 +1,38 @@
1
+ .metric
2
+ &.fail
3
+ background-color: red
4
+
5
+ &.pass
6
+ background-color: green
7
+
8
+ &.unknown
9
+ background-color: grey
10
+
11
+ .metrics-list
12
+ margin: 50px
13
+
14
+ a.metric
15
+ @include clearfix()
16
+ padding: 10px 20px
17
+ display: block
18
+ color: black
19
+ text-decoration: none
20
+ font-size: 20px
21
+ margin-bottom: 5px
22
+
23
+ .name
24
+ float: left
25
+ font-weight: bold
26
+
27
+ .value
28
+ float: right
29
+
30
+ .stale-time
31
+ background-color: #333
32
+ color: #CCCCCC
33
+ display: inline-block
34
+ padding: 0 5px
35
+ border-radius: 4px
36
+ font-weight: normal
37
+ float: left
38
+ margin-right: 10px
@@ -0,0 +1,4 @@
1
+ module BrokenWindow
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,48 @@
1
+ module BrokenWindow
2
+ class MetricsController < ApplicationController
3
+ layout 'broken_window/application'
4
+
5
+ def index
6
+ @metrics = Metric.roots.map {|metric| MeasuredMetric.new(metric)}
7
+ @status = MetricStatus.combine(@metrics.map(&:status))
8
+ @body_class = 'background-metric'
9
+ end
10
+
11
+ def show
12
+ @metric = MeasuredMetric.find(params[:id])
13
+ @status = @metric.status
14
+ end
15
+
16
+ def new
17
+ @metric = Metric.new
18
+ end
19
+
20
+ def create
21
+ @metric = Metric.new(metric_params)
22
+ if @metric.save
23
+ redirect_to @metric
24
+ else
25
+ render action: :new
26
+ end
27
+ end
28
+
29
+ def edit
30
+ @metric = Metric.find(params[:id])
31
+ end
32
+
33
+ def update
34
+ @metric = Metric.find(params[:id])
35
+ if @metric.update_attributes(metric_params)
36
+ redirect_to @metric
37
+ else
38
+ render action: :edit
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def metric_params
45
+ params[:metric].permit(:name, :threshold, :value_type, :calculator, :arguments, :threshold_type, :parent_id)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,4 @@
1
+ module BrokenWindow
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,54 @@
1
+ module BrokenWindow
2
+ class MeasuredMetric
3
+ attr_reader :metric
4
+
5
+ class << self
6
+ def find(param)
7
+ new(BrokenWindow::Metric.find(param))
8
+ end
9
+ end
10
+
11
+ def initialize(metric)
12
+ @metric = metric
13
+ end
14
+
15
+ def measurement
16
+ @measurement ||= @metric.latest_measurement unless container?
17
+ end
18
+
19
+ def status
20
+ @status ||= calculate_status
21
+ end
22
+
23
+ def old?
24
+ measurement && measurement.created_at < 3.days.ago
25
+ end
26
+
27
+ def children
28
+ @metric.children.map do |metric|
29
+ self.class.new(metric)
30
+ end
31
+ end
32
+
33
+ def self.model_name
34
+ Metric.model_name
35
+ end
36
+
37
+ def to_model
38
+ metric
39
+ end
40
+
41
+ delegate :name, :to_param, :threshold, :value_type, :threshold_type, :container?, to: :metric
42
+ delegate :value, to: :measurement, allow_nil: true
43
+
44
+ private
45
+
46
+ def calculate_status
47
+ if container?
48
+ MetricStatus.combine(children.map(&:status))
49
+ else
50
+ StatusChecker.check_status(@metric, measurement)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,7 @@
1
+ module BrokenWindow
2
+ class Measurement < ActiveRecord::Base
3
+ belongs_to :metric
4
+
5
+ scope :latest_first, -> { order("created_at DESC") }
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ module BrokenWindow
2
+ class Metric < ActiveRecord::Base
3
+ VALUE_TYPES = %w(percentage integer)
4
+ THRESHOLD_TYPES = %w(min max)
5
+ VALID_CLASS_NAME = /\A[A-Z][a-zA-Z_0-9\:]*\z/
6
+
7
+ has_many :measurements
8
+
9
+ validates :name, presence: true, length: {maximum: 255}
10
+ validates :calculator, format: {
11
+ with: VALID_CLASS_NAME, allow_blank: true, message: "must be a valid class name" }
12
+ validates :value_type, inclusion: {in: VALUE_TYPES}
13
+ validates :threshold, presence: true, numericality: {allow_blank: true}, unless: :container?
14
+ validates :threshold_type, inclusion: {in: THRESHOLD_TYPES}
15
+
16
+ acts_as_tree order: "name"
17
+
18
+ def latest_measurement
19
+ measurements.latest_first.first
20
+ end
21
+
22
+ def arguments_hash
23
+ if arguments.present?
24
+ YAML::load(arguments)
25
+ else
26
+ {}
27
+ end
28
+ end
29
+
30
+ def self.format_value(value, value_type)
31
+ formatter = "BrokenWindow::Formatters::#{value_type.camelize}".constantize.new
32
+ formatter.call(value)
33
+ end
34
+
35
+ def container?
36
+ calculator.blank?
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,37 @@
1
+ module BrokenWindow
2
+ class MetricStatus
3
+ NAMES = [:fail, :unknown, :pass]
4
+
5
+ class << self
6
+ def pass
7
+ new(:pass)
8
+ end
9
+
10
+ def unknown
11
+ new(:unknown)
12
+ end
13
+
14
+ def fail
15
+ new(:fail)
16
+ end
17
+
18
+ def combine(states)
19
+ states.min
20
+ end
21
+ end
22
+
23
+ attr_reader :value
24
+
25
+ def initialize(name)
26
+ @value = NAMES.index(name)
27
+ end
28
+
29
+ def to_s
30
+ NAMES[@value].to_s
31
+ end
32
+
33
+ def <=>(other)
34
+ value <=> other.value
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ module BrokenWindow
2
+ module Formatters
3
+ class Integer
4
+ include ActionView::Helpers::NumberHelper
5
+
6
+ def call(value)
7
+ value.to_i.to_s if value
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module BrokenWindow
2
+ module Formatters
3
+ class Percentage
4
+ include ActionView::Helpers::NumberHelper
5
+
6
+ def call(value)
7
+ number_to_percentage(value, precision: 0) if value
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module BrokenWindow
2
+ class Measurer
3
+ include Service
4
+
5
+ def call
6
+ Metric.all.each do |metric|
7
+ MetricMeasurer.call(metric)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ module BrokenWindow
2
+ class MetricMeasurer
3
+ include Service
4
+
5
+ def initialize(metric)
6
+ @metric = metric
7
+ end
8
+
9
+ def call
10
+ value = calculator.call
11
+ @metric.measurements.create!(value: value)
12
+ end
13
+
14
+ private
15
+
16
+ def calculator
17
+ calculator_class.new(ActiveSupport::HashWithIndifferentAccess.new(@metric.arguments_hash))
18
+ end
19
+
20
+ def calculator_class
21
+ raise ArgumentError unless @metric.calculator
22
+
23
+ @metric.calculator.constantize
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ module BrokenWindow
2
+ module Service
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+
6
+ # From http://brewhouse.io/blog/2014/04/30/gourmet-service-objects.html
7
+ # Possible responses
8
+ # 1: Fail loudly
9
+ # 2: Return ActiveRecord results
10
+ # 3: Response object
11
+ # Some services have several outcomes and complex error handling. They return a response object which responds to success? and error(s).
12
+ def call
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ def call(*args)
19
+ new(*args).call
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ module BrokenWindow
2
+ class StatusChecker
3
+ class << self
4
+ def check_status(metric, measurement = nil)
5
+ measurement ||= metric.latest_measurement
6
+ if measurement
7
+ if value_passes_threshold?(measurement.value, metric.threshold, metric.threshold_type)
8
+ BrokenWindow::MetricStatus.pass
9
+ else
10
+ BrokenWindow::MetricStatus.fail
11
+ end
12
+ else
13
+ BrokenWindow::MetricStatus.unknown
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def value_passes_threshold?(value, threshold, threshold_type)
20
+ if value
21
+ value.send(comparison_method(threshold_type), threshold)
22
+ end
23
+ end
24
+
25
+ def comparison_method(threshold_type)
26
+ case threshold_type
27
+ when 'min'
28
+ return '>=';
29
+ when 'max'
30
+ return '<=';
31
+ else
32
+ raise "unknown threshold_type #{threshold_type.inspect}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,10 @@
1
+ <% if target.errors.any? %>
2
+ <div class="error_explanation">
3
+ <h2><%= pluralize(target.errors.count, "error") %> prevented this record from being saved:</h2>
4
+ <ul>
5
+ <% target.errors.full_messages.each do |msg| %>
6
+ <li><%= msg %></li>
7
+ <% end %>
8
+ </ul>
9
+ </div>
10
+ <% end %>
@@ -0,0 +1,35 @@
1
+ <%= form_for @metric do |f| %>
2
+ <%= render "error_messages", :target => @metric %>
3
+
4
+ <div class="form-group">
5
+ <%= f.label :name %>
6
+ <%= f.text_field :name, class: 'form-control' %>
7
+ </div>
8
+ <div class="form-group">
9
+ <%= f.label :calculator %>
10
+ <%= f.select :calculator, BrokenWindow.calculators.map(&:name), {include_blank: true}, class: 'form-control' %>
11
+ </div>
12
+ <div class="form-group">
13
+ <%= f.label :value_type %>
14
+ <%= f.select :value_type, BrokenWindow::Metric::VALUE_TYPES, class: 'form-control' %>
15
+ </div>
16
+ <div class="form-group">
17
+ <%= f.label :threshold %>
18
+ <%= f.text_field :threshold, class: 'form-control' %>
19
+ </div>
20
+ <div class="form-group">
21
+ <%= f.label :threshold_type %>
22
+ <%= f.select :threshold_type, BrokenWindow::Metric::THRESHOLD_TYPES, class: 'form-control' %>
23
+ </div>
24
+ <div class="form-group">
25
+ <%= f.label :arguments %>
26
+ <%= f.text_field :arguments, class: 'form-control' %>
27
+ </div>
28
+ <div class="form-group">
29
+ <%= f.label :parent_id %>
30
+ <%= f.text_field :parent_id, class: 'form-control' %>
31
+ </div>
32
+ <button type="submit" class="btn btn-default">Submit</button>
33
+ or
34
+ <%= link_to 'cancel', root_path %>
35
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <div class="metrics-list">
2
+ <% metrics.each do |metric| %>
3
+ <%= link_to(metric, class: "metric #{metric.status}") do %>
4
+ <% if metric.old? %>
5
+ <span class="stale-time">
6
+ <%= time_ago_in_words(metric.measurement.created_at) %> old
7
+ </span>
8
+ <% end %>
9
+ <span class="name"><%= metric.name %></span>
10
+ <div class="value"><%= BrokenWindow::Metric.format_value metric.value, metric.value_type %></div>
11
+ <% end %>
12
+ <% end %>
13
+ </div>
@@ -0,0 +1,5 @@
1
+ <div class="container">
2
+ <h1>Edit Metric</h1>
3
+
4
+ <%= render 'form' %>
5
+ </div>
@@ -0,0 +1,4 @@
1
+ <%= render partial: 'list', locals: {metrics: @metrics} %>
2
+ <div class="page-actions">
3
+ <%= link_to '', new_metric_path, class: 'fa fa-plus' %>
4
+ </div>
@@ -0,0 +1,5 @@
1
+ <div class="container">
2
+ <h1>New Metric</h1>
3
+
4
+ <%= render 'form' %>
5
+ </div>
@@ -0,0 +1,17 @@
1
+ <%= link_to '', metrics_path, class: 'back-link fa fa-level-up' %>
2
+
3
+ <div class="show-metric">
4
+ <h1><%= @metric.name %></h1>
5
+ <%- unless @metric.container? %>
6
+ <div class="value"><%= BrokenWindow::Metric.format_value @metric.value, @metric.value_type %></div>
7
+ <div class="required">
8
+ <div class="minimum"><%= @metric.threshold_type %> <%= BrokenWindow::Metric.format_value @metric.threshold, @metric.value_type %></div>
9
+ </div>
10
+ <%- end %>
11
+ </div>
12
+
13
+ <%= render partial: 'list', locals: {metrics: @metric.children} %>
14
+
15
+ <div class="page-actions">
16
+ <%= link_to '', edit_metric_path(@metric), class: 'fa fa-pencil-square-o' %>
17
+ </div>
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>BrokenWindow</title>
5
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
6
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
7
+ <%= stylesheet_link_tag "broken_window/application", media: "all" %>
8
+ <%= javascript_include_tag "broken_window/application" %>
9
+ <%= csrf_meta_tags %>
10
+ </head>
11
+ <body class="<%= [@status.to_s, @body_class].compact.join(' ') %>">
12
+
13
+ <%= yield %>
14
+
15
+ </body>
16
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ BrokenWindow::Engine.routes.draw do
2
+ resources :metrics, path: '/'
3
+ root to: "metrics#index"
4
+ end
@@ -0,0 +1,13 @@
1
+ class CreateBrokenWindowMetrics < ActiveRecord::Migration
2
+ def change
3
+ create_table :broken_window_metrics do |t|
4
+ t.string :name
5
+ t.string :calculator
6
+ t.string :value_type
7
+ t.text :arguments
8
+ t.decimal :threshold
9
+ t.string :threshold_type
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ class CreateBrokenWindowMeasurements < ActiveRecord::Migration
2
+ def change
3
+ create_table :broken_window_measurements do |t|
4
+ t.integer :metric_id
5
+ t.decimal :value
6
+ t.datetime :created_at
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class AddParentIdToMetrics < ActiveRecord::Migration
2
+ def change
3
+ add_column :broken_window_metrics, :parent_id, :integer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module BrokenWindow
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace BrokenWindow
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module BrokenWindow
2
+ VERSION = "1.1.0"
3
+ end
@@ -0,0 +1,14 @@
1
+ require "broken_window/engine"
2
+
3
+ module BrokenWindow
4
+ class << self
5
+ def register_calculators(calculators)
6
+ @calculators ||= []
7
+ @calculators = @calculators + calculators
8
+ end
9
+
10
+ def calculators
11
+ @calculators
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ namespace :broken_window do
2
+ desc "Take measurements for all metrics"
3
+ task :measure => :environment do
4
+ BrokenWindow::Measurer.call
5
+ end
6
+ end
7
+
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: broken_window
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Craig Ambrose
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-19 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: 4.1.12
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.1.12
27
+ - !ruby/object:Gem::Dependency
28
+ name: acts_as_tree
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: combustion
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Calculate metrics and display a simple broken/not broken dashboard.
84
+ email:
85
+ - craig.ambrose@enspiral.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - MIT-LICENSE
91
+ - README.rdoc
92
+ - Rakefile
93
+ - app/assets/javascripts/broken_window/application.js
94
+ - app/assets/stylesheets/broken_window/application.scss
95
+ - app/assets/stylesheets/broken_window/layout.sass
96
+ - app/assets/stylesheets/broken_window/metric.sass
97
+ - app/assets/stylesheets/broken_window/metrics_list.sass
98
+ - app/controllers/broken_window/application_controller.rb
99
+ - app/controllers/broken_window/metrics_controller.rb
100
+ - app/helpers/broken_window/application_helper.rb
101
+ - app/models/broken_window/measured_metric.rb
102
+ - app/models/broken_window/measurement.rb
103
+ - app/models/broken_window/metric.rb
104
+ - app/models/broken_window/metric_status.rb
105
+ - app/services/broken_window/formatters/integer.rb
106
+ - app/services/broken_window/formatters/percentage.rb
107
+ - app/services/broken_window/measurer.rb
108
+ - app/services/broken_window/metric_measurer.rb
109
+ - app/services/broken_window/service.rb
110
+ - app/services/broken_window/status_checker.rb
111
+ - app/views/broken_window/metrics/_error_messages.html.erb
112
+ - app/views/broken_window/metrics/_form.html.erb
113
+ - app/views/broken_window/metrics/_list.html.erb
114
+ - app/views/broken_window/metrics/edit.html.erb
115
+ - app/views/broken_window/metrics/index.html.erb
116
+ - app/views/broken_window/metrics/new.html.erb
117
+ - app/views/broken_window/metrics/show.html.erb
118
+ - app/views/layouts/broken_window/application.html.erb
119
+ - config/routes.rb
120
+ - db/migrate/20160112005320_create_broken_window_metrics.rb
121
+ - db/migrate/20160112010703_create_broken_window_measurements.rb
122
+ - db/migrate/20160419161925_add_parent_id_to_metrics.rb
123
+ - lib/broken_window.rb
124
+ - lib/broken_window/engine.rb
125
+ - lib/broken_window/version.rb
126
+ - lib/tasks/broken_window_tasks.rake
127
+ homepage: http://app.webpunch12.com
128
+ licenses:
129
+ - MIT
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.2.2
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: Show me whether the app is broken or not
151
+ test_files: []