rails-idle 0.0.9

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f58b55e40ca14d9ba36db82d076cc50dc3ccba46
4
+ data.tar.gz: 8bde64f72b2e5dbd54d034132abe534ba2553d1f
5
+ SHA512:
6
+ metadata.gz: ddffde060b6413844c73918b96440a479096c8e53212c2e93f8a7b3d1233148b8c341673ad5d80e9a56793b0b462c091095435d38848f4b975697cb275fb3f84
7
+ data.tar.gz: c5aae1b3eb90f11b0fbf95f8409a3d8efd6ad11529c2123ccdfba2f0a25d47ff71bcfbb16f043d8cb7da08bac3d77bdb422537bd7a74bb00c1d7a4066f3ee9ba
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ tmp
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Vitalik Danchenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,68 @@
1
+ require 'pathname'
2
+ require 'active_support/core_ext/hash'
3
+ require 'active_support/core_ext/string'
4
+
5
+ module RailsIdle
6
+ autoload :Storage, 'rails-idle/storage'
7
+ autoload :Collector, 'rails-idle/collector'
8
+ autoload :TreeBuilder, 'rails-idle/tree_builder'
9
+ autoload :Report, 'rails-idle/report'
10
+ autoload :Web, 'rails-idle/web'
11
+
12
+ DEFAULTS = {
13
+ collectors: RailsIdle::Collector.list,
14
+ reset: false,
15
+ cache: {
16
+ :views => Pathname.new('/tmp/cache/rails-idle/views.cache'),
17
+ },
18
+ }
19
+
20
+ class << self
21
+
22
+ def options
23
+ @options ||= DEFAULTS.dup
24
+ end
25
+
26
+ def options=(opts)
27
+ @options = opts
28
+ end
29
+
30
+ def configure
31
+ yield self
32
+ end
33
+
34
+ def collectors
35
+ options[:collectors]
36
+ end
37
+
38
+ def collectors=(list)
39
+ options[:collectors] = list.map(&:to_sym).select{|c| DEFAULTS[:collectors].include? c}
40
+ end
41
+
42
+ def cache=(hash)
43
+ hash.select{|key, _| DEFAULTS[:collectors].include? key}
44
+ _cache = hash.symbolize_keys.select{|c, _| DEFAULTS[:collectors].include? c}
45
+ options[:cache].merge!(_cache)
46
+ end
47
+
48
+ def reset?
49
+ options[:reset]
50
+ end
51
+
52
+ def reset=(value)
53
+ options[:reset] = value
54
+ end
55
+
56
+ def stylesheets
57
+ @stylesheets ||= []
58
+ end
59
+
60
+ def stylesheets=(sheets = [])
61
+ @stylesheets = sheets
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ require 'rails-idle/railtie' if defined?(::Rails)
@@ -0,0 +1,21 @@
1
+ module RailsIdle
2
+ module Collector
3
+ autoload :Base, 'rails-idle/collector/base'
4
+ #autoload :Actions, 'rails-idle/collector/actions'
5
+ autoload :Views, 'rails-idle/collector/views'
6
+ # autoload :Stylesheets, 'rails-idle/collector/stylesheets'
7
+
8
+ class << self
9
+
10
+ def list
11
+ [:views]
12
+ end
13
+
14
+ def instance(key)
15
+ return RailsIdle::Collector::Views.instance if key == :views
16
+ # return RailsIdle::Collector::Stylesheets.instance if key == :stylesheets
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ require 'singleton'
2
+
3
+ module RailsIdle
4
+ module Collector
5
+ class Base
6
+ include Singleton
7
+
8
+ def collect
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def subscribe
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def push(item, execution_time = 1)
17
+ storage.add(item, execution_time)
18
+ end
19
+
20
+ def storage
21
+ @starage ||= RailsIdle::Storage::RailsCache.new
22
+ end
23
+
24
+ protected
25
+
26
+ def collector_key
27
+ self.class.to_s.demodulize.downcase.to_sym
28
+ end
29
+
30
+ private
31
+
32
+ def _collect(path)
33
+ storage.reset(path) if RailsIdle.reset?
34
+ storage.add(path)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,92 @@
1
+ module RailsIdle
2
+ module Collector
3
+ class Views < Base
4
+ def collect
5
+ view_paths.each do |path|
6
+ views = Dir[path + '/**/*.*']
7
+ views.each do |view|
8
+ view = modify_prefix(view)
9
+ next unless view
10
+ if view =~ extensions_regexp
11
+ _collect view
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ def subscribe
18
+ %w{render_template render_partial render_collection}.each do |event|
19
+ ActiveSupport::Notifications.subscribe("#{event}.action_view") do |name, started, finished, unique_id, payload|
20
+ orig_prefix = ''
21
+ view = modify_prefix payload[:identifier], orig_prefix
22
+ next unless view
23
+ execution_time = finished.to_f - started.to_f
24
+ push(view, execution_time)
25
+ if payload[:layout] && view =~ /\.\w+\.\w+$/
26
+ # just_view = extract_view payload[:identifier], view
27
+ # prefix = payload[:identifier].gsub(just_view, '')
28
+ extension = view.match(/\.\w+\.\w+$/)[0]
29
+ layout = orig_prefix + '/' + payload[:layout] + extension
30
+ layout = modify_prefix layout
31
+ push(layout, execution_time) if layout
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def view_paths
40
+ ActionController::Base.new.view_paths.map(&:to_path)
41
+ end
42
+
43
+ def extensions_regexp
44
+ @extensions_regexp ||= build_extensions_regexp
45
+ end
46
+
47
+ def build_extensions_regexp
48
+ formats = %w(html text)
49
+ handlers = ActionView::Template.template_handler_extensions
50
+ exts = view_extentions.join('|').gsub(/\./, '\.')
51
+ Regexp.new "(#{exts})$"
52
+ end
53
+
54
+ def view_extentions
55
+ @view_extentions ||= build_view_extentions
56
+ end
57
+
58
+ def build_view_extentions
59
+ extentions = []
60
+ format_extensions = %w(html text)
61
+ handler_extensions = ActionView::Template.template_handler_extensions
62
+ handler_extensions.each do |handler_ext|
63
+ extentions << ".#{handler_ext}"
64
+ format_extensions.each do |format_ext|
65
+ extentions << ".#{format_ext}.#{handler_ext}"
66
+ end
67
+ end
68
+ extentions
69
+ end
70
+
71
+ def modify_prefix(identifier, orig_prefix = '')
72
+ view_paths.each do |path|
73
+ orig_prefix.replace path
74
+ return identifier.gsub(path, path.gsub('/', '&#47;')) if identifier.start_with?(path)
75
+ end
76
+ orig_prefix.replace ''
77
+ nil
78
+ end
79
+
80
+ # def extract_view(orig_prefix, modified_prefix)
81
+ # idx = 1
82
+ # view = ''
83
+ # while (idx <= orig_prefix.size && idx <= modified_prefix.size && orig_prefix[-idx] == modified_prefix[-idx])
84
+ # view = modified_prefix[-idx] + view
85
+ # idx += 1
86
+ # end
87
+ # view
88
+ # end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,22 @@
1
+ module RailsIdle
2
+ class << self
3
+ def init!
4
+ collect
5
+ subscribe
6
+ end
7
+
8
+ private
9
+
10
+ def _collectors
11
+ Hash[*(RailsIdle::Collector.list.map{|c| [c, RailsIdle::Collector.instance(c)]}.flatten)]
12
+ end
13
+
14
+ def collect
15
+ _collectors.select{|k, _| options[:collectors].include? k}.each_value(&:collect)
16
+ end
17
+
18
+ def subscribe
19
+ _collectors.select{|k, _| options[:collectors].include? k}.each_value(&:subscribe)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails-idle/init'
2
+
3
+ module RailsIdle
4
+ class Railtie < ::Rails::Railtie
5
+ config.to_prepare do
6
+ RailsIdle.init!
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ module RailsIdle
2
+ class Report
3
+ CALCULATED_KEY = :calculated
4
+ COUNTER_KEY = RailsIdle::Storage::COUNTER_KEY
5
+
6
+ def initialize(collector)
7
+ @tree = TreeBuilder.new(collector).tree
8
+ end
9
+
10
+ def prepare
11
+ calc_counter!(@tree)
12
+ #sort!(@obj)
13
+ @tree
14
+ end
15
+
16
+ private
17
+
18
+ def calc_counter!(obj)
19
+ return obj[COUNTER_KEY] if obj[COUNTER_KEY].is_a?(Fixnum)
20
+ return obj[CALCULATED_KEY] if obj[CALCULATED_KEY].is_a?(Fixnum)
21
+ obj[CALCULATED_KEY] = obj.inject(0) do |sum, (key, nested_obj)|
22
+ sum + (key.is_a?(Symbol) ? 0 : calc_counter!(nested_obj))
23
+ end
24
+ obj[CALCULATED_KEY]
25
+ end
26
+
27
+ def sort!(obj)
28
+ obj.each do |k, v|
29
+ obj[k] = sort!(v) if v.is_a?(Hash)
30
+ end
31
+ obj.sort_by do |k, v|
32
+ if v.is_a?(Hash)
33
+ v[CALCULATED_KEY] || v[COUNTER_KEY] || 0
34
+ else
35
+ Float::INFINITY
36
+ end
37
+ end.to_h
38
+ end
39
+
40
+
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ module RailsIdle
2
+ module Storage
3
+ COUNTER_KEY = :counter
4
+ EXECUTION_KEY = :execution
5
+
6
+ autoload :Base, 'rails-idle/storage/base'
7
+ autoload :RailsCache, 'rails-idle/storage/rails_cache'
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ module RailsIdle
2
+ module Storage
3
+ class Base
4
+
5
+ def add(path, execution_time = nil)
6
+ add_to_list path
7
+ end
8
+
9
+ def get(path, key)
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def reset(path)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def objects_list
18
+ @objects_list ||= empty_list
19
+ end
20
+
21
+ private
22
+
23
+ def empty_list
24
+ []
25
+ end
26
+
27
+ def add_to_list(path)
28
+ objects_list << path
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ module RailsIdle
2
+ module Storage
3
+ class RailsCache < Base
4
+
5
+ def add(path, execution_time = nil)
6
+ super
7
+ if execution_time
8
+ increment(path, COUNTER_KEY)
9
+ increment(path, EXECUTION_KEY, (execution_time * 1000).round)
10
+ end
11
+ end
12
+
13
+ def get(path, key)
14
+ begin
15
+ Rails.cache.read build_name(path, key)
16
+ rescue Exception => e # Redis workaround
17
+ (Rails.cache.read build_name(path, key), raw: true).to_i
18
+ end
19
+ end
20
+
21
+ def reset(path)
22
+ [COUNTER_KEY, EXECUTION_KEY].each do |key|
23
+ Rails.cache.delete build_name(path, key)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def increment(path, key, amount = 1)
30
+ Rails.cache.increment build_name(path, key), amount
31
+ end
32
+
33
+ def build_name(path, key)
34
+ "#{RailsIdle}.#{path}.#{key}"
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ module RailsIdle
2
+ class TreeBuilder
3
+ def initialize(collector)
4
+ @storage = collector.storage
5
+ end
6
+
7
+ def tree
8
+ @tree ||= build_tree
9
+ end
10
+
11
+ private
12
+
13
+ def build_tree
14
+ root = {}
15
+ @storage.objects_list.each do |path|
16
+ items = parse_path(path)
17
+ tree = root
18
+ items.each do |item|
19
+ tree[item] = {} unless tree[item]
20
+ tree = tree[item]
21
+ end
22
+ tree[RailsIdle::Storage::COUNTER_KEY] = @storage.get(path, RailsIdle::Storage::COUNTER_KEY)
23
+ tree[RailsIdle::Storage::EXECUTION_KEY] = @storage.get(path, RailsIdle::Storage::EXECUTION_KEY)
24
+ end
25
+ root
26
+ end
27
+
28
+ def parse_path(path)
29
+ path.split(/,|\/|::/)
30
+ end
31
+
32
+ end
33
+ end