scribbler 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scribbler (0.0.2)
4
+ scribbler (0.1.0)
5
5
  activesupport
6
6
  thor
7
7
 
data/README.markdown CHANGED
@@ -15,7 +15,7 @@ Currently it assists in:
15
15
 
16
16
  In your Rails project add
17
17
 
18
- gem scribbler
18
+ gem 'scribbler'
19
19
 
20
20
  to your Gemfile and
21
21
 
@@ -1,7 +1,4 @@
1
1
  module Scribbler
2
- # TODO not sure this'll work
3
- delegate :configure, :to => :Base
4
- delegate :log, :to => :Base
5
2
  class Base
6
3
  # Gets the path of this Gem
7
4
  #
@@ -67,6 +64,7 @@ module Scribbler
67
64
  class_eval(&block)
68
65
  Base.include_in_application
69
66
  BaseIncluder.include_includeables
67
+ build_methods
70
68
  end
71
69
 
72
70
  # Simply returns the configurator class.
@@ -81,7 +79,119 @@ module Scribbler
81
79
  Scribbler::Configurator
82
80
  end
83
81
 
82
+ # Public: Save ourselves some repetition. Notifies error to NewRelic
83
+ # and drops given string into a given log.
84
+ #
85
+ # location - Either a pathname from the above method or symbol for an above
86
+ # method
87
+ # options - Hash of options for logging on Ngin
88
+ # :error - Error object, mostly for passing to NewRelic
89
+ # :message - Message to log in the actual file
90
+ # :custom_fields - Custom fields dropped into the default template
91
+ # :template - Whether or not to use the template at this log
92
+ # :new_relic - Notify NewRelic of the error (default: true)
93
+ #
94
+ # Examples
95
+ #
96
+ # log(Ngin.subseason_log_location, :error => e, :message => "Error message stuff", :new_relic => false)
97
+ #
98
+ # log(:subseason, :error => e, :message => "Error message stuff")
99
+ #
100
+ # log(:subseason, :message => "Logging like a bauss")
101
+ #
102
+ # Returns Nothing.
103
+ def self.log(location, options={})
104
+ options = {
105
+ :template => config.use_template_by_default
106
+ }.merge options
107
+ begin
108
+ NewRelic::Agent.notice_error(options[:error]) if options[:error] and options[:new_relic] != false
109
+ rescue NameError
110
+ nil
111
+ end
112
+
113
+ apply_to_log location, options
114
+ end
115
+
84
116
  private
117
+ # Builds the message and any other options into a string
118
+ # using the template defined in the configure
119
+ #
120
+ # options - options hash that comprises most of the important log pieces
121
+ # :message - The message we're wrapping into the templater [required]
122
+ # :template - Whether or not to use the template method
123
+ # **Other option information given in the .log docs
124
+ #
125
+ # Examples
126
+ #
127
+ # Base.build_with_template(:message => "...", :template => false)
128
+ # # => "..."
129
+ #
130
+ # Base.build_with_template
131
+ # # => nil
132
+ #
133
+ # Base.build_with_template(:message => "...", :template => true)
134
+ # # => <<-EXAMPLE
135
+ # --------------------
136
+ # TEMPLATE STUFF
137
+ # ....
138
+ # EXAMPLE
139
+ #
140
+ # Returns nil, a string, or a string built with calling the Configurator.template method
141
+ def self.build_with_template(options={})
142
+ if options[:message].present?
143
+ options[:message] = options[:message].strip_heredoc.rstrip
144
+ options[:template] ? config.template.call(options) : options[:message]
145
+ end
146
+ end
147
+
148
+ # Drops built message into the log with the given location
149
+ #
150
+ # location - location either found with Base.*_log_location or by hoping a valid
151
+ # path string or Path object were passed
152
+ # options - options hash
153
+ # :message - Message to be built and put in log file [required]
154
+ # ** Other hash information given in Base.log
155
+ #
156
+ # Examples
157
+ #
158
+ # Base.apply_to_log :some_loc, :message => "...", :template => false, :error => e
159
+ # # => Nothing
160
+ #
161
+ # Returns Nothing
162
+ def self.apply_to_log(location, options={})
163
+ if location.present? and options[:message].present?
164
+ log = File.open(find_file_at(location), 'a')
165
+ log.puts build_with_template(options)
166
+ log.close
167
+ end
168
+ end
169
+
170
+ # Attempts to turn a symbol or string into the *_log_location method that
171
+ # was auto-build based on Configurator.logs and finds the file path
172
+ #
173
+ # location - a string or symbol that will be turned into a *_log_location
174
+ # method
175
+ #
176
+ # Examples
177
+ #
178
+ # Base.find_file_at :a_file
179
+ # # => <#Path:...> # The method `a_file_log_location` exists
180
+ #
181
+ # Base.find_file_at :another_file
182
+ # # => :another_file # The method `another_file_log_location` does not exist
183
+ #
184
+ # Returns Nothing
185
+ #
186
+ # TODO: allow the log base directory to be set in configurator
187
+ def self.find_file_at(location)
188
+ if location.is_a?(Symbol) or location.is_a?(String)
189
+ real_method = location.to_s + "_log_location"
190
+ location = respond_to?(real_method) ? send(real_method) : location.to_s
191
+ end
192
+ location
193
+ end
194
+
85
195
  # If the config agrees, attempt to include our special methods
86
196
  # in the main application object.
87
197
  #
@@ -91,7 +201,8 @@ module Scribbler
91
201
  # # => Nothing
92
202
  #
93
203
  # Returns Nothing
94
- # TODO Allow config to define where we send the include
204
+ #
205
+ # TODO: Allow config to define where we send the include
95
206
  def self.include_in_application
96
207
  if config.application_include
97
208
  begin
@@ -1,15 +1,142 @@
1
1
  module Scribbler
2
2
  class Configurator
3
3
  class << self
4
- attr_accessor :logs, :application_include
4
+ attr_accessor :logs, :application_include, :template, :use_template_by_default, :log_directory
5
5
  end
6
6
 
7
+ # Provides location for getting the directory Scribbler will place
8
+ # log files in. Favors RailsApplication/log/ but falls back to
9
+ # $PWD/log if not set in config
10
+ #
11
+ # Examples
12
+ #
13
+ # Configurator.log_directory
14
+ # # => "/some/path/to/log/"
15
+ #
16
+ # Returns String for log directory location
17
+ def self.log_directory
18
+ @log_directory ||= begin
19
+ Rails.root.join('log')
20
+ rescue NameError
21
+ File.join Dir.pwd, 'log'
22
+ end
23
+ end
24
+
25
+ # List of strings or symbols that represent logs we want methods
26
+ # generated for
27
+ #
28
+ # Default: []
29
+ #
30
+ # Examples
31
+ #
32
+ # Scribbler::Configurator.logs
33
+ # # => ['copy', 'destroy']
34
+ #
35
+ # Returns list of logs
7
36
  def self.logs
8
37
  @logs ||= []
9
38
  end
10
39
 
40
+ # Boolean used for deciding whether or not Scribbler should
41
+ # define #*_log_location methods and a .log method in a rails application
42
+ #
43
+ # Default: false
44
+ #
45
+ # Examples
46
+ #
47
+ # Scribbler::Configurator.application_include
48
+ # # => false
49
+ #
50
+ # Returns boolean
51
+ #
52
+ # TODO: Allow the class we're sending the include to to be custom
11
53
  def self.application_include
12
54
  @application_include || false
13
55
  end
56
+
57
+ # Boolean for deciding if we should use the logger template by
58
+ # by default when calling Base.log
59
+ #
60
+ # Default: false
61
+ #
62
+ # Examples
63
+ #
64
+ # Scribbler::Configurator.use_template_by_default
65
+ # # => false
66
+ #
67
+ # Returns boolean
68
+ def self.use_template_by_default
69
+ @use_template_by_default || false
70
+ end
71
+
72
+ # The method that sets a template for each log made with
73
+ # Base.log
74
+ #
75
+ # The template proc is given the whole options hash that is
76
+ # passed through Base.log or YourApplication.log. So if you
77
+ # had:
78
+ #
79
+ # YourApplication.log :a_log,
80
+ # :message => "information data",
81
+ # :custom => "stuff"
82
+ #
83
+ # Then you can assume the template proc will get:
84
+ #
85
+ # options = {
86
+ # :message => "information data",
87
+ # :custom => "stuff"
88
+ # }
89
+ #
90
+ # To set a custom template:
91
+ #
92
+ # Scribbler::Configurator.template = proc do |options|
93
+ # "Message: options[:message]"
94
+ # end
95
+ #
96
+ # From Scribbler::Base.configure that would be:
97
+ #
98
+ # config.template = proc do |options|
99
+ # "Message: options[:message]"
100
+ # end
101
+ #
102
+ # **Keep in mind** that the template can be ignored at any
103
+ # Base.log call with:
104
+ #
105
+ # Base.log :your_log, :template => false, :message "..."
106
+ #
107
+ # Default:
108
+ #
109
+ # -------------------------------------------------
110
+ # SomeObject: #{id} # options[:object] and options[:object].try(:id)
111
+ # Custom1: some good info # options[:custom_fields] hash
112
+ # Custom2: some better info # Left of colon is the key.humanize, right is the value
113
+ # OH NO YOU BROKED STUFF # options[:message].strip_heredoc
114
+ # DO PLX FIX #
115
+ #
116
+ # Examples
117
+ #
118
+ # Scribbler::Configurator.template
119
+ # # => <#Proc:...>
120
+ #
121
+ # Returns the proc that wraps around each log entry
122
+ #
123
+ # TODO: Block input that would break this
124
+ # TODO: Test
125
+ def self.template
126
+ @template ||= proc do |options|
127
+ begin
128
+ if_id = options[:object].id
129
+ rescue NoMethodError
130
+ if_id = "no id"
131
+ end
132
+ custom_fields = options[:custom_fields].to_a.collect { |x| "#{x[0].to_s.humanize}: #{x[1]}" }.join("\n")
133
+
134
+ template = "-------------------------------------------------\n"
135
+ template << "#{Time.now}\n"
136
+ template << "#{options[:object].class.name}: #{if_id}\n" if options[:object]
137
+ template << "#{custom_fields}\n" if custom_fields.present?
138
+ template << "#{options[:message]}\n\n"
139
+ end
140
+ end
14
141
  end
15
142
  end
@@ -11,7 +11,7 @@ module Scribbler
11
11
  # Returns Nothing
12
12
  # TODO Rework; there must be a more sane way of including these
13
13
  def self.include_includeables
14
- Scribbler::Base.send :include, Scribbler::Includeables
14
+ Base.send :include, Scribbler::Includeables
15
15
  end
16
16
  end
17
17
 
@@ -37,8 +37,7 @@ module Scribbler
37
37
  # Returns Pathname to log
38
38
  Scribbler::Base.config.logs.each do |value|
39
39
  define_singleton_method "#{value}_log_location" do
40
- Rails.root.join('log', "#{value}.log")
41
- #TODO remove dependence on Rails here
40
+ File.join Scribbler::Configurator.log_directory, "#{value}.log"
42
41
  end
43
42
  end
44
43
  end
@@ -63,26 +62,7 @@ module Scribbler
63
62
  #
64
63
  # Returns Nothing.
65
64
  def log(location, options={})
66
- begin
67
- NewRelic::Agent.notice_error(options[:error]) if options[:error] and options[:new_relic] != false
68
- rescue NameError
69
- nil
70
- end
71
-
72
- real_location = location
73
- if real_location.is_a?(Symbol) or real_location.is_a?(String)
74
- real_method = location.to_s + "_log_location"
75
- real_location = self.send(real_method) if self.respond_to? real_method
76
- real_location = real_location.to_s
77
- end
78
-
79
- #if File.exists?(real_location) and options[:message].present?
80
- if options[:message].present?
81
- message = options[:message].strip_heredoc
82
- log = File.open(real_location, 'a')
83
- log.puts message
84
- log.close
85
- end
65
+ Scribbler::Base.log(location, options)
86
66
  end
87
67
  end
88
68
  end
@@ -1,3 +1,3 @@
1
1
  module Scribbler
2
- VERSION = '0.0.2'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -6,6 +6,7 @@ module Scribbler
6
6
 
7
7
  before :each do
8
8
  Object.send :remove_const, :Rails if defined?(Rails) == 'constant' && Rails.class == Class
9
+ Time.stub :now => "now"
9
10
  end
10
11
 
11
12
  it "should give me a configurator" do
@@ -34,6 +35,7 @@ module Scribbler
34
35
  describe "configure" do
35
36
  it "kicks off the module and sends includes" do
36
37
  subject.should_receive(:include_in_application).once
38
+ subject.should_receive(:build_methods).once # Twice if we didn't stub below method
37
39
  BaseIncluder.should_receive(:include_includeables).once
38
40
  subject.configure do
39
41
  end
@@ -46,5 +48,110 @@ module Scribbler
46
48
  subject.config.application_include.should be_true
47
49
  end
48
50
  end
51
+
52
+ describe "build with template" do
53
+ let(:some_object) { stub(:id => "no id", :class => stub(:name => "SomeObject")) }
54
+ before :each do
55
+ subject.configure do
56
+ config.application_include = false
57
+ end
58
+ end
59
+
60
+ it "calls log, skips templater and still works" do
61
+ Scribbler::Base.send(:build_with_template,
62
+ :object => some_object,
63
+ :template => false,
64
+ :message => "test\n123").should == "test\n123"
65
+ end
66
+
67
+ it "calls log and gets message with template wrapper" do
68
+ Scribbler::Base.send(:build_with_template,
69
+ :object => some_object,
70
+ :template => true,
71
+ :message => <<-MSG
72
+ test
73
+ 123
74
+ MSG
75
+ ).should == <<-MSG.strip_heredoc
76
+ -------------------------------------------------
77
+ now
78
+ SomeObject: no id
79
+ test
80
+ 123
81
+
82
+ MSG
83
+ end
84
+
85
+ it "calls log and gets message with custom params" do
86
+ Scribbler::Base.send(:build_with_template,
87
+ :template => true,
88
+ :object => some_object,
89
+ :custom_fields => {:test1 => 1, :test2 => 2},
90
+ :message => <<-MSG
91
+ test
92
+ 123
93
+ MSG
94
+ ).should == <<-MSG.strip_heredoc
95
+ -------------------------------------------------
96
+ now
97
+ SomeObject: no id
98
+ Test1: 1
99
+ Test2: 2
100
+ test
101
+ 123
102
+
103
+ MSG
104
+ end
105
+ end
106
+
107
+ describe "apply to log" do
108
+ before :each do
109
+ subject.configure do
110
+ config.logs = %w[test_log]
111
+ end
112
+ end
113
+
114
+ it "should not work without location" do
115
+ subject.apply_to_log(nil, :message => "...").should be_nil
116
+ end
117
+
118
+ it "should not work without message" do
119
+ subject.should_not_receive :test_log_log_location
120
+ subject.apply_to_log(:test_log).should be_nil
121
+ end
122
+
123
+ it "should build a template and try to put it in a file" do
124
+ options = { :message => "..." }
125
+ subject.should_receive(:send).with "test_log_log_location"
126
+ subject.should_receive(:build_with_template).with options
127
+ file_stub = stub
128
+ file_stub.should_receive :puts
129
+ file_stub.should_receive :close
130
+ File.should_receive(:open) { file_stub }
131
+ subject.apply_to_log :test_log, options
132
+ end
133
+ end
134
+
135
+ describe "find file at" do
136
+ it "doesn't find a file method" do
137
+ # in case we have bad config data lingering
138
+ subject.stub(:respond_to?).with('test_log_log_location').and_return false
139
+ subject.should_not_receive(:test_log_log_location)
140
+ subject.find_file_at(:test_log).should == 'test_log'
141
+ end
142
+
143
+ it "finds a file method defined" do
144
+ subject.configure do
145
+ config.logs = %w[test_log]
146
+ end
147
+ subject.should_receive(:test_log_log_location).once
148
+ subject.find_file_at :test_log
149
+ end
150
+
151
+ it "isn't a string or a symbol and just returns the input" do
152
+ path = Pathname.new '/'
153
+ subject.find_file_at(path).should be(path)
154
+ end
155
+ end
49
156
  end
50
157
  end
@@ -21,5 +21,34 @@ module Scribbler
21
21
  subject.application_include.should == true
22
22
  end
23
23
  end
24
+
25
+ describe "log directory" do
26
+ it "tries a rails root when Rails defined" do
27
+ root_stub = stub
28
+ root_stub.should_receive(:join).with 'log'
29
+ Rails = stub(:root => root_stub)
30
+ subject.log_directory
31
+ end
32
+
33
+ it "falls back to pwd/log without rails" do
34
+ dir = "dir/"
35
+ Rails.should_receive(:root).and_raise(NameError)
36
+ Dir.should_receive(:pwd).and_return('dir')
37
+ subject.log_directory.should == 'dir/log'
38
+ end
39
+
40
+ it "sets the log directory" do
41
+ var_log = File.new "/var/log"
42
+ subject.log_directory = var_log
43
+ subject.log_directory.should == var_log
44
+ subject.log_directory = nil
45
+
46
+ # Check the reset
47
+ Rails.should_receive(:root).and_raise(NameError)
48
+ Dir.should_receive(:pwd).and_return('dir')
49
+ subject.log_directory.should == 'dir/log'
50
+ subject.log_directory
51
+ end
52
+ end
24
53
  end
25
54
  end
@@ -3,15 +3,66 @@ Scribbler::Base.configure do
3
3
  # Unless you'd like to experiment with breaking things and battling dragons,
4
4
  # please only use what we document here.
5
5
  #
6
- # Alter the path to the configuration yaml. If you alter those variables
7
- # from this config, those here will take precedence. Don't confuse yourself
8
- # by having thos options here and there.
9
- #
10
- # config.yaml_config_path = Rails.root.join('config', 'scribbler.yml')
11
- #
12
6
  # Include the log methods to the rails application. So, if you have an
13
7
  # application called Blog you can do Blog.log(...), rather than
14
8
  # Scribbler.log(...). Default: false
15
9
  #
16
10
  # config.application_include = true
11
+ #
12
+ #
13
+ # What directory should these logs be placed in? The default is
14
+ # to try the Rails log directory and fallback to the $PWD/log path
15
+ #
16
+ # config.log_directory = File.new '/a/better/path'
17
+ #
18
+ #
19
+ # A list of the logs you'd like location methods for. if the logs list
20
+ # has:
21
+ #
22
+ # ['log1']
23
+ #
24
+ # You are afforded a Base.log1_log_location method and you may do:
25
+ #
26
+ # Base.log :log1, ....
27
+ #
28
+ # REQUIRED
29
+ #
30
+ # config.logs = %w[log1 log2]
31
+ #
32
+ # This option enables log templating. Each time you log a message you
33
+ # can have it automatically wrapped in some sugar. The default is something
34
+ # like:
35
+ #
36
+ # -------------------------------------------------
37
+ # SomeObject: #{id} # options[:object] and options[:object].try(:id)
38
+ # Custom1: some good info # options[:custom_fields] hash
39
+ # Custom2: some better info # Left of colon is the key.humanize, right is the value
40
+ # OH NO YOU BROKED STUFF # options[:message].strip_heredoc
41
+ # DO PLX FIX #
42
+ #
43
+ # If you would rather this not be default you may set this to false. Keep
44
+ # in mind, there is an option on the Base.log to enable or disable the
45
+ # template on a per-call basis. (:template)
46
+ #
47
+ # config.use_template_by_default = true # Default: false
48
+ #
49
+ #
50
+ # Don't like the default template above? Write your own proc here.
51
+ # The proc is given the options hash that you give to Base.log so you're
52
+ # given plenty of control over what information you have to work with.
53
+ #
54
+ # options - Hash of options for logging on Ngin
55
+ # :error - Error object, mostly for passing to NewRelic
56
+ # :message - Message to log in the actual file [REQUIRED]
57
+ # :custom_fields - Custom fields dropped into the default template
58
+ # :template - Whether or not to use the template at this log
59
+ # :new_relic - Notify NewRelic of the error (default: true)
60
+ #
61
+ # config.template = proc do |options|
62
+ # <<-MSG
63
+ # ##########
64
+ # Cool template bro!
65
+ # Message: #{options[:message]}
66
+ # MSG
67
+ # end
17
68
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scribbler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-20 00:00:00.000000000 Z
12
+ date: 2012-06-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -140,7 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
140
140
  version: '0'
141
141
  segments:
142
142
  - 0
143
- hash: -2255771618684195708
143
+ hash: -504908089194974695
144
144
  required_rubygems_version: !ruby/object:Gem::Requirement
145
145
  none: false
146
146
  requirements:
@@ -149,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
149
  version: '0'
150
150
  segments:
151
151
  - 0
152
- hash: -2255771618684195708
152
+ hash: -504908089194974695
153
153
  requirements: []
154
154
  rubyforge_project:
155
155
  rubygems_version: 1.8.24