merb_inspector 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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
+