merb_inspector 0.3.2

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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Maiha <maiha@wota.jp>
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 ADDED
@@ -0,0 +1,39 @@
1
+ merb_inspector
2
+ ==============
3
+
4
+ A plugin for the Merb framework that provides "inspect" helper.
5
+ Just inspect your objects! No longer need to prepare views, scaffold and pagination.
6
+
7
+
8
+ Setup
9
+ =====
10
+
11
+ 1. load gem at the bottom of config/dependencies.rb
12
+
13
+ require "merb_inspector"
14
+
15
+ 2. include css and js in your view or layout files
16
+
17
+ <%= css_include_tag "merb_inspector.css" -%>
18
+ <%= js_include_tag "jquery.js" -%>
19
+
20
+
21
+ Example
22
+ =======
23
+
24
+ just *inspect* the object you want to know!
25
+
26
+ <%= inspect [1, :hello] %>
27
+ <%= inspect ENV.to_hash %>
28
+ <%= inspect User.all(:limit=>10) %>
29
+ <%= inspect @item %>
30
+ ...
31
+
32
+ of course you can see available inspectors as following
33
+
34
+ <%= inspect Merb::Inspector::Manager.stores %>
35
+
36
+
37
+ Copyright (c) 2008 maiha@wota.jp, released under the MIT license
38
+
39
+
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ require 'merb-core'
5
+ require 'merb-core/tasks/merb'
6
+
7
+ GEM_NAME = "merb_inspector"
8
+ GEM_VERSION = "0.3.2"
9
+ AUTHOR = "Maiha"
10
+ EMAIL = "maiha@wota.jp"
11
+ HOMEPAGE = "http://github.com/maiha/merb_inspector"
12
+ SUMMARY = "Merb plugin that provides powerful 'inspect' helper method"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.rubyforge_project = 'merb'
16
+ s.name = GEM_NAME
17
+ s.version = GEM_VERSION
18
+ s.platform = Gem::Platform::RUBY
19
+ s.has_rdoc = true
20
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
21
+ s.summary = SUMMARY
22
+ s.description = s.summary
23
+ s.author = AUTHOR
24
+ s.email = EMAIL
25
+ s.homepage = HOMEPAGE
26
+ s.add_dependency('merb', '>= 1.0.8')
27
+ s.require_path = 'lib'
28
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec,inspectors,templates,mirror}/**/*")
29
+
30
+ end
31
+
32
+ Rake::GemPackageTask.new(spec) do |pkg|
33
+ pkg.gem_spec = spec
34
+ end
35
+
36
+ desc "install the plugin as a gem"
37
+ task :install do
38
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
39
+ end
40
+
41
+ desc "Uninstall the gem"
42
+ task :uninstall do
43
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
44
+ end
45
+
46
+ desc "Create a gemspec file"
47
+ task :gemspec do
48
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
49
+ file.puts spec.to_ruby
50
+ end
51
+ end
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/merb_inspector.rb
5
+ Add your Merb rake tasks to lib/merb_inspector/merbtasks.rb
@@ -0,0 +1,5 @@
1
+ class ArrayInspector < Merb::Inspector
2
+ builtin
3
+ model Array
4
+ lead :size=>[40,20,15]
5
+ end
@@ -0,0 +1,4 @@
1
+ class BasicInspector < Merb::Inspector
2
+ builtin
3
+ model Merb::Request, StringIO, IO, String, Symbol, Numeric, Class
4
+ end
@@ -0,0 +1,172 @@
1
+ class DataMapper::ResourceInspector < Merb::Inspector
2
+ builtin
3
+ model ::DataMapper::Resource
4
+
5
+ def edit(object, options = {})
6
+ @object = object
7
+ @options = options
8
+ @mode = :edit
9
+
10
+ execute
11
+ end
12
+
13
+ private
14
+ def model
15
+ @object.class
16
+ end
17
+
18
+ def klass
19
+ @object.class
20
+ end
21
+
22
+ def columns
23
+ @columns ||= build_columns
24
+ end
25
+
26
+ def dom_id
27
+ oid = @object.new_record? ? "new" : @object.id
28
+ "#{resource_name}-#{oid}"
29
+ end
30
+
31
+ def template
32
+ if @options[:action].to_s == 'new'
33
+ "new"
34
+ else
35
+ "record"
36
+ end
37
+ end
38
+
39
+ def save_action
40
+ if @object.new_record?
41
+ "/" + resource_name
42
+ else
43
+ resource(@object)
44
+ end
45
+ end
46
+
47
+ def options
48
+ {:model=>model, :record=>@object, :save_action=>save_action, :toggle=>toggle}
49
+ end
50
+
51
+ ######################################################################
52
+ ### Resourceful
53
+
54
+ def resource_name
55
+ Extlib::Inflection.demodulize(model.name).plural.snake_case
56
+ end
57
+
58
+ def link_to_new(label = 'New', opts = {})
59
+ link_to label, resource(resource_name, :new), opts
60
+ rescue Merb::Router::GenerationError
61
+ end
62
+
63
+ def show_link_value(record, p, opts = {})
64
+ opts[:label] ||= "Show"
65
+ link_to opts[:label], resource(record), opts
66
+ rescue Merb::Router::GenerationError
67
+ end
68
+
69
+ def edit_link_value(record, p, opts = {})
70
+ opts[:label] ||= "Edit"
71
+ link_to opts[:label], resource(record, :edit), opts
72
+ rescue Merb::Router::GenerationError
73
+ end
74
+
75
+ def delete_link_value(record, p, opts = {})
76
+ opts[:label] ||= "Delete"
77
+ link_to opts[:label], resource(record, :delete), opts
78
+ rescue Merb::Router::GenerationError
79
+ end
80
+
81
+ ######################################################################
82
+ ### form builder for DataMapper
83
+
84
+ def default_columns
85
+ [LinkColumn.new(self, :show), LinkColumn.new(self, :edit)]
86
+ end
87
+
88
+ def find_column_by_name(name)
89
+ name = name.to_s.intern
90
+ (klass.properties.to_a + default_columns).each do |col|
91
+ return col if col.name == name
92
+ end
93
+ return nil
94
+ end
95
+
96
+ def build_columns
97
+ if @options[:only]
98
+ valids = Array(@options[:only]).flatten.compact.map(&:to_sym)
99
+ cols = valids.map{|name| find_column_by_name(name) || name}
100
+ else
101
+ cols = klass.properties.to_a + default_columns
102
+ if @options[:except]
103
+ invalids = Array(@options[:except]).flatten.compact.map(&:to_sym)
104
+ cols = cols.reject{|col| invalids.include?(col.name)}
105
+ end
106
+ end
107
+
108
+ cols.map do |col|
109
+ case col
110
+ when ::DataMapper::Property
111
+ DMColumn.new(self, col)
112
+ when Column
113
+ col
114
+ else
115
+ VirtualColumn.new(self, col)
116
+ end
117
+ end
118
+ end
119
+
120
+ def column_label(column)
121
+ column.label
122
+ end
123
+
124
+ def column_value(record, column)
125
+ column.value(record)
126
+ rescue Column::MethodFound => e
127
+ __send__ *e.args
128
+ rescue Column::NotDefined => e
129
+ call_user_method(e.message, record, column)
130
+ end
131
+
132
+ def column_form(record, column)
133
+ column.form(record)
134
+ rescue Column::MethodFound => e
135
+ __send__ *e.args
136
+ rescue Column::NotDefined => e
137
+ call_user_method(e.message, record, column)
138
+ end
139
+
140
+ def call_user_method(method, record, column)
141
+ method = method.to_sym
142
+ block = @options[:columns][method] rescue nil
143
+ if block
144
+ block.call(record, column)
145
+ else
146
+ "[VirtualColumn] '#{method}' is not defined yet"
147
+ end
148
+ end
149
+ end
150
+
151
+
152
+ class DataMapper::CollectionInspector < DataMapper::ResourceInspector
153
+ builtin
154
+ model ::DataMapper::Collection, ::DataMapper::Associations::OneToMany::Proxy
155
+
156
+ private
157
+ def model
158
+ @object.query.model
159
+ end
160
+
161
+ def klass
162
+ @object
163
+ end
164
+
165
+ def options
166
+ {:model=>model, :records=>@object}
167
+ end
168
+
169
+ def template
170
+ "records"
171
+ end
172
+ end
@@ -0,0 +1,5 @@
1
+ class HashInspector < Merb::Inspector
2
+ builtin
3
+ model Hash
4
+ lead :size=>[40,20,15]
5
+ end
@@ -0,0 +1,153 @@
1
+ class MongoMapper::DocumentInspector < Merb::Inspector
2
+ builtin
3
+ model ::MongoMapper::Document
4
+
5
+ def edit(object, options = {})
6
+ @object = object
7
+ @options = options
8
+ @mode = :edit
9
+
10
+ execute
11
+ end
12
+
13
+ private
14
+ def model
15
+ @object.class
16
+ end
17
+
18
+ def klass
19
+ @object.class
20
+ end
21
+
22
+ def columns
23
+ @columns ||= build_columns
24
+ end
25
+
26
+ def dom_id
27
+ oid = @object.new_record? ? "new" : @object.id
28
+ "#{resource_name}-#{oid}"
29
+ end
30
+
31
+ def template
32
+ if @options[:action].to_s == 'new'
33
+ "new"
34
+ else
35
+ "record"
36
+ end
37
+ end
38
+
39
+ def save_action
40
+ if @object.new_record?
41
+ "/" + resource_name
42
+ else
43
+ resource(@object)
44
+ end
45
+ end
46
+
47
+ def options
48
+ {:model=>model, :record=>@object, :save_action=>save_action, :toggle=>toggle}
49
+ end
50
+
51
+ ######################################################################
52
+ ### Resourceful
53
+
54
+ def resource_name
55
+ Extlib::Inflection.demodulize(model.name).plural.snake_case
56
+ end
57
+
58
+ def link_to_new(label = 'New', opts = {})
59
+ link_to label, resource(resource_name, :new), opts
60
+ rescue Merb::Router::GenerationError
61
+ end
62
+
63
+ def show_link_value(record, p, opts = {})
64
+ opts[:label] ||= "Show"
65
+ link_to opts[:label], resource(record), opts
66
+ rescue Merb::Router::GenerationError
67
+ end
68
+
69
+ def edit_link_value(record, p, opts = {})
70
+ opts[:label] ||= "Edit"
71
+ link_to opts[:label], resource(record, :edit), opts
72
+ rescue Merb::Router::GenerationError
73
+ end
74
+
75
+ def delete_link_value(record, p, opts = {})
76
+ opts[:label] ||= "Delete"
77
+ link_to opts[:label], resource(record, :delete), opts
78
+ rescue Merb::Router::GenerationError
79
+ end
80
+
81
+ ######################################################################
82
+ ### form builder for DataMapper
83
+
84
+ def default_columns
85
+ [LinkColumn.new(self, :show), LinkColumn.new(self, :edit)]
86
+ end
87
+
88
+ def all_columns
89
+ default_columns
90
+ end
91
+
92
+ def find_column_by_name(name)
93
+ name = name.to_s.intern
94
+ all_columns.each do |col|
95
+ return col if col.name == name
96
+ end
97
+ return nil
98
+ end
99
+
100
+ def build_columns
101
+ if @options[:only]
102
+ valids = Array(@options[:only]).flatten.compact.map(&:to_sym)
103
+ cols = valids.map{|name| find_column_by_name(name) || name}
104
+ else
105
+ cols = all_columns
106
+ if @options[:except]
107
+ invalids = Array(@options[:except]).flatten.compact.map(&:to_sym)
108
+ cols = cols.reject{|col| invalids.include?(col.name)}
109
+ end
110
+ end
111
+
112
+ cols.map do |col|
113
+ case col
114
+ when ::DataMapper::Property
115
+ DMColumn.new(self, col)
116
+ when Column
117
+ col
118
+ else
119
+ VirtualColumn.new(self, col)
120
+ end
121
+ end
122
+ end
123
+
124
+ def column_label(column)
125
+ column.label
126
+ end
127
+
128
+ def column_value(record, column)
129
+ column.value(record)
130
+ rescue Column::MethodFound => e
131
+ __send__ *e.args
132
+ rescue Column::NotDefined => e
133
+ call_user_method(e.message, record, column)
134
+ end
135
+
136
+ def column_form(record, column)
137
+ column.form(record)
138
+ rescue Column::MethodFound => e
139
+ __send__ *e.args
140
+ rescue Column::NotDefined => e
141
+ call_user_method(e.message, record, column)
142
+ end
143
+
144
+ def call_user_method(method, record, column)
145
+ method = method.to_sym
146
+ block = @options[:columns][method] rescue nil
147
+ if block
148
+ block.call(record, column)
149
+ else
150
+ "[VirtualColumn] '#{method}' is not defined yet"
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,11 @@
1
+ class ObjectInspector < Merb::Inspector
2
+ builtin
3
+ private
4
+ def template
5
+ if instance_variables.empty?
6
+ :plain
7
+ else
8
+ :default
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ # make sure we're running inside Merb
2
+ if defined?(Merb::Plugins)
3
+
4
+ $: << File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__))
5
+
6
+ # Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
7
+ Merb::Plugins.config[:merb_inspector] = {
8
+ :chickens => false
9
+ }
10
+
11
+ Merb::BootLoader.before_app_loads do
12
+ require "merb_inspector" / "inspector"
13
+ require "merb_inspector" / "data"
14
+ require "merb_inspector" / "builtin"
15
+ require "merb_inspector" / "manager"
16
+ require "merb_inspector" / "helper"
17
+
18
+ Merb::Inspector::Manager.reset
19
+ Merb::Inspector::Manager.install
20
+ end
21
+
22
+ Merb::BootLoader.after_app_loads do
23
+
24
+ # class ::Application
25
+ # include Merb::Inspector::Helper
26
+ # end
27
+ end
28
+
29
+ Merb::Plugins.add_rakefiles "merb_inspector/merbtasks"
30
+ end
@@ -0,0 +1,14 @@
1
+ module Merb
2
+ class Inspector
3
+ module Builtin
4
+ private
5
+ def dir
6
+ Merb::Inspector.root + "templates" + name
7
+ end
8
+
9
+ def template_for(name)
10
+ dir + name.to_s
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,129 @@
1
+ module Merb
2
+ class Inspector
3
+ class Column # Abstract
4
+ class Delegate < StandardError; end
5
+ class NotDefined < Delegate; end
6
+ class MethodFound < Delegate
7
+ attr_reader :args
8
+ def initialize(*args)
9
+ @args = args
10
+ super("method delegation")
11
+ end
12
+ end
13
+
14
+ attr_accessor :context, :name
15
+
16
+ def initialize(context, name)
17
+ @context = context
18
+ @name = name.to_s.intern
19
+ end
20
+
21
+ def label(*)
22
+ name
23
+ end
24
+
25
+ def value(record)
26
+ # first, search class prefixed method that user override
27
+ evaluate(record, "#{Extlib::Inflection.demodulize(record.class.name)}_#{name}_value")
28
+
29
+ # second, search method that user override
30
+ evaluate(record, "#{name}_value")
31
+
32
+ # finally, guess form from property type
33
+ default_value(record)
34
+ end
35
+
36
+ def form(record)
37
+ # first, search class prefixed method that user override
38
+ evaluate(record, "#{Extlib::Inflection.demodulize(record.class.name)}_#{name}_form")
39
+
40
+ # second, search method that user override
41
+ evaluate(record, "#{name}_form")
42
+
43
+ # finally, guess form from property type
44
+ default_form(record)
45
+ end
46
+
47
+ private
48
+ def h(str)
49
+ context.h(str)
50
+ end
51
+
52
+ def evaluate(record, method)
53
+ raise MethodFound.new(method, record, self) if context.respond_to?(method, true)
54
+ end
55
+
56
+ def default_value(record)
57
+ raise NotImplementedError
58
+ end
59
+
60
+ def default_form(record)
61
+ raise NotImplementedError
62
+ end
63
+
64
+ def not_defined(method)
65
+ raise NotDefined, method
66
+ end
67
+ end
68
+
69
+ class DMColumn < Column
70
+ def initialize(context, property)
71
+ @context = context
72
+ @property = property
73
+ end
74
+
75
+ def name
76
+ @property.name.to_s
77
+ end
78
+
79
+ def type
80
+ @property.type
81
+ end
82
+
83
+ def default_value(record)
84
+ value = record.send(name)
85
+ if type == ::DataMapper::Types::Text
86
+ value.to_s.split(/\r?\n/).map{|i| h(i.to_s)}.join("<BR>")
87
+ else
88
+ h(value.to_s)
89
+ end
90
+ end
91
+
92
+ def default_form(record)
93
+ if type == ::DataMapper::Types::Serial
94
+ record.send name
95
+ elsif type == ::DataMapper::Types::Text
96
+ raise MethodFound.new(:text_area, name.to_sym)
97
+ else
98
+ raise MethodFound.new(:text_field, name.to_sym)
99
+ end
100
+ end
101
+ end
102
+
103
+ class VirtualColumn < Column
104
+ def default_value(record)
105
+ not_defined("#{name}_value")
106
+ end
107
+
108
+ def default_form(record)
109
+ not_defined("#{name}_form")
110
+ end
111
+ end
112
+
113
+ class LinkColumn < Column
114
+ def default_value(record)
115
+ evaluate(record, "#{name}_link_value")
116
+ not_defined("#{name}_link_value")
117
+ end
118
+
119
+ def default_form(record)
120
+ evaluate(record, "#{name}_link_form")
121
+ not_defined("#{name}_link_form")
122
+ end
123
+
124
+ def label
125
+ nil
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,42 @@
1
+ module Merb
2
+ class Inspector
3
+ module Helper
4
+ def inspect(*args)
5
+ return h(super()) if args.blank?
6
+ object = args.shift
7
+ options = args.shift || {}
8
+
9
+ unless options.is_a?(Hash)
10
+ action = options.to_s
11
+ options = args.shift || {}
12
+ options[:action] = action
13
+ end
14
+ options[:action] ||= :show
15
+ options[:level] ||= 1
16
+ options[:max_level] ||= 3
17
+
18
+ # validate keys
19
+ valid_keys = [:action, :level, :max_level, :only, :except, :columns, :lead]
20
+ unknown_keys = options.keys - valid_keys
21
+ if !unknown_keys.blank?
22
+ return h("[INSPECTOR ERROR] Unknown key(s): %s" % unknown_keys.inspect)
23
+ end
24
+
25
+ inspector_class = BasicInspector if options[:level] >= options[:max_level]
26
+ inspector_class ||= Manager.lookup(object) || Merb::Inspector.default
27
+
28
+ inspector = inspector_class.new(Merb::Request.new({}))
29
+ if inspector.respond_to?(options[:action])
30
+ inspector.send options[:action], object, options
31
+ else
32
+ message = "%s doesn't recognize '%s' action" % [inspector.class, options[:action]]
33
+ raise Merb::Inspector::ActionNotFound, message
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ class Merb::Controller
41
+ include Merb::Inspector::Helper
42
+ end
@@ -0,0 +1,148 @@
1
+ module Merb
2
+ class Inspector < Merb::Controller
3
+ ######################################################################
4
+ ### for exceptins
5
+
6
+ class Merb::Inspector::ActionNotFound < Merb::ControllerExceptions::ActionNotFound; end
7
+
8
+ ######################################################################
9
+ ### for module
10
+
11
+ def self.root
12
+ @root ||= Pathname(File.expand_path(File.dirname(__FILE__) + "/../../"))
13
+ end
14
+
15
+ def self.default
16
+ ObjectInspector
17
+ end
18
+
19
+ ######################################################################
20
+ ### for class
21
+
22
+ def self.model(*models)
23
+ models.each do |model|
24
+ Merb::Inspector::Manager.register(model, self)
25
+ end
26
+ end
27
+
28
+ def self.builtin
29
+ include Merb::Inspector::Builtin
30
+ end
31
+
32
+ def self.lead(options = {})
33
+ @lead_options = options
34
+ end
35
+
36
+ def self.lead_options
37
+ @lead_options
38
+ end
39
+
40
+ def show(object, options = {})
41
+ @object = object
42
+ @options = options
43
+
44
+ execute
45
+ end
46
+
47
+ private
48
+ def name
49
+ self.class.name.sub(/^Merb::/,'').sub(/Inspector$/,'').snake_case.gsub(/::/, '/')
50
+ end
51
+
52
+ def dom_id
53
+ @object.class.name.plural.snake_case.gsub(/::/,'-') + '-' + @object.object_id.to_s
54
+ end
55
+
56
+ def toggle
57
+ "$('##{dom_id} > .reversible').toggle();return false;"
58
+ end
59
+
60
+ def template_for(name)
61
+ name.to_s
62
+ end
63
+
64
+ def main
65
+ partial template_for(template), current_options
66
+ end
67
+
68
+ def execute
69
+ if lead?
70
+ wrapped_main
71
+ else
72
+ main
73
+ end
74
+ end
75
+
76
+ def close_lead_label
77
+ "[x]"
78
+ end
79
+
80
+ def lead_size
81
+ sizes = Array((self.class.lead_options || {})[:size]).compact
82
+ sizes[level-1] || sizes[-1] || 15
83
+ end
84
+
85
+ def lead?
86
+ case @options[:lead]
87
+ when NilClass
88
+ self.class.lead_options
89
+ else
90
+ !! @options[:lead]
91
+ end
92
+ end
93
+
94
+ def lead
95
+ "<span class=nowrap>%s</span>" % h(@object.inspect.truncate(lead_size))
96
+ end
97
+
98
+ def link_to_lead
99
+ link_to close_lead_label, "#", :onclick=>toggle
100
+ end
101
+
102
+ def link_to_main
103
+ link_to lead, "#", :onclick=>toggle
104
+ end
105
+
106
+ def template
107
+ :default
108
+ end
109
+
110
+ def current_options
111
+ basic_options.merge(options)
112
+ end
113
+
114
+ def options
115
+ {}
116
+ end
117
+
118
+ def level
119
+ @options[:level]
120
+ end
121
+
122
+ def basic_options
123
+ {:options=>@options, :level=>level}
124
+ end
125
+
126
+ def child_options
127
+ {:level=>@options[:level]+1, :max_level=>@options[:max_level]}
128
+ end
129
+
130
+ def wrapped_main
131
+ <<-HTML
132
+ <div id="#{dom_id}">
133
+ <div id="#{dom_id}_lead" class="reversible" style="display:block;">
134
+ #{link_to_main}
135
+ </div>
136
+ <div id="#{dom_id}_main" class="reversible" style="display:none;">
137
+ <div style="float:right;">#{link_to_lead}</div>
138
+ #{main}
139
+ </div>
140
+ </div>
141
+ HTML
142
+ end
143
+ end
144
+
145
+ def self.inspector
146
+ Merb::Inspector
147
+ end
148
+ end
@@ -0,0 +1,99 @@
1
+ module Merb
2
+ class Inspector
3
+ module Manager
4
+ ######################################################################
5
+ ### for module
6
+
7
+ class << self
8
+ attr_accessor :stores
9
+ attr_accessor :caches
10
+ end
11
+
12
+ def self.reset
13
+ self.stores = Hash.new
14
+ self.caches = Hash.new
15
+
16
+ log = Merb.root / "log" / "inspector.log"
17
+ File.unlink log if File.exist?(log)
18
+ load_builtin_inspectors
19
+ end
20
+
21
+ def self.load_builtin_inspectors
22
+ inspector_dir = File.dirname(__FILE__) / "../../inspectors"
23
+ Dir["#{inspector_dir}/*.rb"].sort.each do |file|
24
+ begin
25
+ require file
26
+ rescue Exception => error
27
+ message = "[MerbInspector] load error: #{error} (#{error.class})\n#{error.backtraces.first rescue nil}"
28
+ Merb.logger.error message
29
+ end
30
+ end
31
+ end
32
+
33
+ def self.log(message)
34
+ path = Merb.root / "log" / "inspector.log"
35
+ message = "[Inspector] %s" % message.to_s.strip
36
+ File.open(path, "a+") {|f| f.puts message}
37
+ end
38
+
39
+ def self.register(klass, inspector)
40
+ action = stores.has_key?(klass) ? "overridden" : "registered"
41
+ stores[klass] = inspector
42
+ log "%s %s -> %s" % [action, klass, inspector]
43
+ end
44
+
45
+ def self.lookup(object)
46
+ # first, search object itself for mainly class stuff
47
+ if stores.has_key?(object)
48
+ log "lookup: %s => %s" % [object, stores[object]]
49
+ return stores[object]
50
+ end
51
+
52
+ # second, search its class
53
+ if caches.has_key?(object.class)
54
+ log "lookup: %s => %s (cached)" % [object.class, caches[object.class] || 'nil']
55
+ return caches[object.class]
56
+ end
57
+
58
+ # finally, search ancestors of the class
59
+ klass = object.class.ancestors.find{|klass|
60
+ log "lookup: %s = %s ... %s" % [object.class, klass, stores[klass]]
61
+ stores.has_key?(klass)
62
+ }
63
+ caches[object.class] = stores[klass]
64
+ if klass
65
+ log "lookup: %s => %s (registered)" % [object.class, caches[object.class]]
66
+ else
67
+ log "lookup: %s => nil (registered as negative cache)" % [object.class]
68
+ end
69
+ return stores[klass]
70
+ end
71
+
72
+ ######################################################################
73
+ ### Install
74
+
75
+ def self.install
76
+ mirror("public/stylesheets")
77
+ end
78
+
79
+ def self.mirror(dir)
80
+ source_dir = File.join(File.dirname(__FILE__), '..', '..', 'mirror', dir)
81
+ target_dir = File.join(Merb.root, dir)
82
+ FileUtils.mkdir_p(target_dir) unless File.exist?(target_dir)
83
+
84
+ Dir[source_dir + "/*"].each do |src|
85
+ time = File.mtime(src)
86
+ file = File.basename(src)
87
+ dst = File.join(target_dir, file)
88
+
89
+ next if File.directory?(src)
90
+ next if File.exist?(dst) and File.mtime(dst) >= time
91
+ FileUtils.copy(src, dst)
92
+ File.utime(time, time, dst)
93
+ command = File.exist?(dst) ? "update" : "install"
94
+ log "#{command}: #{dir}/#{file}"
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,6 @@
1
+ namespace :merb_inspector do
2
+ desc "Do something for merb_inspector"
3
+ task :default do
4
+ puts "merb_inspector doesn't do anything"
5
+ end
6
+ end
@@ -0,0 +1,91 @@
1
+ span.nowrap {
2
+ white-space: nowrap;
3
+ }
4
+
5
+ table.inspector {
6
+ border-collapse:collapse;
7
+ }
8
+
9
+
10
+ table.inspector th {
11
+ background-color: #555;
12
+ text-align: left;
13
+ }
14
+
15
+ table.inspector th a,
16
+ table.inspector th p {
17
+ font: bold 11px arial, sans-serif;
18
+ display: block;
19
+ background-color: #555;
20
+ }
21
+
22
+ table.inspector th a {
23
+ color: #fff;
24
+ padding: 2px 15px 2px 5px;
25
+ }
26
+
27
+ table.inspector th p {
28
+ color: #eee;
29
+ padding: 2px 5px;
30
+ }
31
+
32
+ table.inspector th a:hover {
33
+ background-color: #000;
34
+ color: #ff8;
35
+ }
36
+
37
+ table.inspector > tbody > tr.record td {
38
+ background-color: #E6F2FF;
39
+ }
40
+
41
+ table.inspector > tbody > tr.record > td {
42
+ padding: 5px 4px;
43
+ color: #333;
44
+ font-family: Verdana, sans-serif;
45
+ font-size: 11px;
46
+ border-bottom: solid 1px #C5DBF7;
47
+ border-left: solid 1px #C5DBF7;
48
+ }
49
+
50
+ table.inspector > tbody > tr.even-record td {
51
+ background-color: #fff;
52
+ }
53
+
54
+ table.inspector > tbody > tr.even-record > td {
55
+ border-left: solid 1px #ddd;
56
+ }
57
+
58
+ table.inspector > tbody > tr.record > td.sorted {
59
+ background-color: #B9DCFF;
60
+ border-bottom: solid 1px #AFD0F5;
61
+ }
62
+
63
+ table.inspector > tbody > tr.even-record > td.sorted {
64
+ background-color: #E6F2FF;
65
+ border-bottom: solid 1px #AFD0F5;
66
+ }
67
+
68
+
69
+
70
+ .record table
71
+ {
72
+ background-color: #fff;
73
+ border-collapse: collapse;
74
+ border-spacing: 0px;
75
+ }
76
+ .record table th
77
+ {
78
+ background-color: #dee7ec;
79
+ border: 1px solid #8cacbb;
80
+ padding: 3px;
81
+ }
82
+ .record table td
83
+ {
84
+ border: 1px solid #8cacbb;
85
+ padding: 3px;
86
+ }
87
+
88
+ table.logical th,
89
+ table.logical td {
90
+ border: 0px;
91
+ }
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "merb_inspector" do
4
+ it "should do nothing" do
5
+ true.should == true
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
@@ -0,0 +1 @@
1
+ <%=h @object.inspect %>
@@ -0,0 +1,18 @@
1
+ <table class="inspector">
2
+ <tr>
3
+ <th><p>index</p></th>
4
+ <th><p>value</p></th>
5
+ <th><p>type</p></th>
6
+ </tr>
7
+ <%- @object.each_with_index do |obj, i| -%>
8
+ <%-
9
+ tr_class = (i % 2 == 0) ? "even-record" : ""
10
+ tr_class += " #{list_row_class(obj)}" if respond_to? :list_row_class
11
+ -%>
12
+ <tr class="record <%=tr_class%>">
13
+ <td align=center><%=i+1%></td>
14
+ <td><%= inspect obj, child_options %></td>
15
+ <td><%=h obj.class.name %></td>
16
+ </tr>
17
+ <%- end -%>
18
+ </table>
@@ -0,0 +1 @@
1
+ <span class=nowrap><%=h @object.inspect.truncate(80) %></span>
@@ -0,0 +1,29 @@
1
+ <div>
2
+ <table class="inspector data-mapper-collection">
3
+ <thead>
4
+ <tr>
5
+ <%- columns.each do |p| -%>
6
+ <th><p><%= column_label(p) %></p></th>
7
+ <%- end -%>
8
+ <th></th>
9
+ </tr>
10
+ </thead>
11
+ <tbody class="records">
12
+ <%- records.each_with_index do |record, i| -%>
13
+ <%-
14
+ tr_class = (i % 2 == 0) ? "even-record" : ""
15
+ tr_class += " #{list_row_class(record)}" if respond_to? :list_row_class
16
+ -%>
17
+ <tr class="record <%=tr_class%>">
18
+ <%- columns.each do |p| -%>
19
+ <td><%= column_value(record, p) %></td>
20
+ <%- end -%>
21
+ </tr>
22
+ <%- end -%>
23
+ </tbody>
24
+ </table>
25
+
26
+ <%= link_to_new 'New' %>
27
+
28
+ </div>
29
+
@@ -0,0 +1,41 @@
1
+ <div id="<%=dom_id%>">
2
+ <div id="<%=dom_id%>_show" class="reversible record show" style="display:<%= (@mode == :edit) ? 'none' : 'display' %>">
3
+ <table>
4
+ <tbody>
5
+ <%- columns.each do |p| -%>
6
+ <tr>
7
+ <th><%= column_label(p) %></th>
8
+ <td><%= column_value(record, p) %></td>
9
+ </tr>
10
+ <%- end -%>
11
+ <tr>
12
+ <td colspan=2 align=center>
13
+ <%= link_to "edit", "#", :onclick=>toggle %>
14
+ </td>
15
+ </tr>
16
+ </tbody>
17
+ </table>
18
+ </div>
19
+
20
+ <div id="<%=dom_id%>_edit" class="reversible record edit" style="display:<%= (@mode == :edit) ? 'display' : 'none' %>">
21
+ <%= form_for record, :action=>save_action do %>
22
+ <table>
23
+ <tbody>
24
+ <%- columns.each do |p| -%>
25
+ <tr>
26
+ <th><%= column_label(p) %></th>
27
+ <td><%= column_form(record, p) %></td>
28
+ </tr>
29
+ <%- end -%>
30
+ <tr>
31
+ <td colspan=2 align=center>
32
+ <%= submit (record.new_record? ? "create" : "update").t %>
33
+ <%= link_to "cancel", "#", :onclick=>toggle unless record.new_record? %>
34
+ </td>
35
+ </tr>
36
+ </tbody>
37
+ </table>
38
+ <% end =%>
39
+ </div>
40
+ </div>
41
+
@@ -0,0 +1,19 @@
1
+ <table class="inspector">
2
+ <tr>
3
+ <th><p>key</p></th>
4
+ <th><p>value</p></th>
5
+ <th><p>type</p></th>
6
+ </tr>
7
+ <%- @object.keys.each_with_index do |key, i| -%>
8
+ <%- obj = @object[key] -%>
9
+ <%-
10
+ tr_class = (i % 2 == 0) ? "even-record" : ""
11
+ tr_class += " #{list_row_class(obj)}" if respond_to? :list_row_class
12
+ -%>
13
+ <tr class="record <%=tr_class%>">
14
+ <td><%= inspect key, child_options %></td>
15
+ <td><%= inspect obj, child_options %></td>
16
+ <td><%=h obj.class.name %></td>
17
+ </tr>
18
+ <%- end -%>
19
+ </table>
@@ -0,0 +1,41 @@
1
+ <div id="<%=dom_id%>">
2
+ <div id="<%=dom_id%>_show" class="reversible record show" style="display:<%= (@mode == :edit) ? 'none' : 'display' %>">
3
+ <table>
4
+ <tbody>
5
+ <%- columns.each do |p| -%>
6
+ <tr>
7
+ <th><%= column_label(p) %></th>
8
+ <td><%= column_value(record, p) %></td>
9
+ </tr>
10
+ <%- end -%>
11
+ <tr>
12
+ <td colspan=2 align=center>
13
+ <%= link_to "edit", "#", :onclick=>toggle %>
14
+ </td>
15
+ </tr>
16
+ </tbody>
17
+ </table>
18
+ </div>
19
+
20
+ <div id="<%=dom_id%>_edit" class="reversible record edit" style="display:<%= (@mode == :edit) ? 'display' : 'none' %>">
21
+ <%= form_for record, :action=>save_action do %>
22
+ <table>
23
+ <tbody>
24
+ <%- columns.each do |p| -%>
25
+ <tr>
26
+ <th><%= column_label(p) %></th>
27
+ <td><%= column_form(record, p) %></td>
28
+ </tr>
29
+ <%- end -%>
30
+ <tr>
31
+ <td colspan=2 align=center>
32
+ <%= submit (record.new_record? ? "create" : "update").t %>
33
+ <%= link_to "cancel", "#", :onclick=>toggle unless record.new_record? %>
34
+ </td>
35
+ </tr>
36
+ </tbody>
37
+ </table>
38
+ <% end =%>
39
+ </div>
40
+ </div>
41
+
@@ -0,0 +1,19 @@
1
+ <table class="inspector">
2
+ <tr>
3
+ <th><p>key</p></th>
4
+ <th><p>value</p></th>
5
+ <th><p>type</p></th>
6
+ </tr>
7
+ <%- @object.instance_variables.sort.each_with_index do |key, i| -%>
8
+ <%- obj = @object.instance_variable_get(key) -%>
9
+ <%-
10
+ tr_class = (i % 2 == 0) ? "even-record" : ""
11
+ tr_class += " #{list_row_class(obj)}" if respond_to? :list_row_class
12
+ -%>
13
+ <tr class="record <%=tr_class%>">
14
+ <td><%=h key %></td>
15
+ <td><%#h obj.inspect %><%= inspect obj, child_options rescue "error" %></td>
16
+ <td><%=h obj.class.name %></td>
17
+ </tr>
18
+ <%- end -%>
19
+ </table>
@@ -0,0 +1 @@
1
+ <%=h @object.inspect %>
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: merb_inspector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.2
5
+ platform: ruby
6
+ authors:
7
+ - Maiha
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-28 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: merb
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.8
24
+ version:
25
+ description: Merb plugin that provides powerful 'inspect' helper method
26
+ email: maiha@wota.jp
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ - LICENSE
34
+ - TODO
35
+ files:
36
+ - LICENSE
37
+ - README
38
+ - Rakefile
39
+ - TODO
40
+ - lib/merb_inspector/helper.rb
41
+ - lib/merb_inspector/builtin.rb
42
+ - lib/merb_inspector/data.rb
43
+ - lib/merb_inspector/merbtasks.rb
44
+ - lib/merb_inspector/manager.rb
45
+ - lib/merb_inspector/inspector.rb
46
+ - lib/merb_inspector.rb
47
+ - spec/spec_helper.rb
48
+ - spec/merb_inspector_spec.rb
49
+ - inspectors/object.rb
50
+ - inspectors/hash.rb
51
+ - inspectors/basic.rb
52
+ - inspectors/mongo_mapper.rb
53
+ - inspectors/data_mapper.rb
54
+ - inspectors/array.rb
55
+ - templates/hash/_default.html.erb
56
+ - templates/_default.html.erb
57
+ - templates/basic/_default.html.erb
58
+ - templates/array/_default.html.erb
59
+ - templates/object/_plain.html.erb
60
+ - templates/object/_default.html.erb
61
+ - templates/data_mapper/resource/_record.html.erb
62
+ - templates/data_mapper/collection/_records.html.erb
63
+ - templates/mongo_mapper/document/_record.html.erb
64
+ - mirror/public/stylesheets/merb_inspector.css
65
+ has_rdoc: true
66
+ homepage: http://github.com/maiha/merb_inspector
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options: []
71
+
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ requirements: []
87
+
88
+ rubyforge_project: merb
89
+ rubygems_version: 1.3.5
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Merb plugin that provides powerful 'inspect' helper method
93
+ test_files: []
94
+