diff --git a/CHANGELOG b/CHANGELOG index c190ad7a..ecacbc24 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ -1.6.2 (unreleased) +2.0.0.beta (unreleased) - Improves spec performance and simplicity (Mauro George) + - Remove the support for Ruby 1.8.x and Rails 2.x (Mauro George) + - New plugin structure, no more unnecessary monkey patching (Mauro George) + - Add the new hash syntax support (Mauro George) - Handle objects that have a custom #to_hash method (Elliot Shank) 1.6.1 diff --git a/README.md b/README.md index fb2b4e51..2d0e462a 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ Awesome Print is a Ruby library that pretty prints Ruby objects in full color exposing their internal structure with proper indentation. Rails ActiveRecord objects and usage within Rails templates are supported via included mixins. -__NOTE__: awesome_print v1.2.0 is the last release supporting Ruby versions -prior to v1.9.3 and Rails versions prior to v3.0. The upcoming awesome_print -v2.0 will *require* Ruby v1.9.3 or later and Rails v3.0 or later. +__NOTE__: awesome_print v1.6.1 is the last release supporting Ruby versions +prior to v1.9.3 and Rails versions prior to v3.2. The upcoming awesome_print +v2.0 will *require* Ruby v1.9.3 or later and Rails v3.2 or later. ### Installation ### # Installing as Ruby gem @@ -33,14 +33,15 @@ ap object, options = {} Default options: ```ruby -:indent => 4, # Indent using 4 spaces. -:index => true, # Display array indices. -:html => false, # Use ANSI color codes rather than HTML. -:multiline => true, # Display in multiple lines. -:plain => false, # Use colors. -:raw => false, # Do not recursively format object instance variables. -:sort_keys => false, # Do not sort hash keys. -:limit => false, # Limit large output for arrays and hashes. Set to a boolean or integer. +:indent => 4, # Indent using 4 spaces. +:index => true, # Display array indices. +:html => false, # Use ANSI color codes rather than HTML. +:multiline => true, # Display in multiple lines. +:plain => false, # Use colors. +:raw => false, # Do not recursively format object instance variables. +:sort_keys => false, # Do not sort hash keys. +:limit => false, # Limit large output for arrays and hashes. Set to a boolean or integer. +:colonize_symbol_keys => false, # Use the foo: 'bar' syntax, when the key is a symbol :color => { :args => :pale, :array => :white, diff --git a/awesome_print.gemspec b/awesome_print.gemspec index 4db950ed..d933fe48 100644 --- a/awesome_print.gemspec +++ b/awesome_print.gemspec @@ -1,13 +1,11 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ +$:.push File.expand_path('../lib', __FILE__) + require "rake" +require 'awesome_print/version' Gem::Specification.new do |s| s.name = "awesome_print" - s.version = "1.6.2" + s.version = AwesomePrint.version # s.platform = Gem::Platform::RUBY s.authors = "Michael Dvorkin" s.date = Time.now.strftime("%Y-%m-%d") diff --git a/init.rb b/init.rb deleted file mode 100644 index b1861774..00000000 --- a/init.rb +++ /dev/null @@ -1 +0,0 @@ -require File.join(File.dirname(__FILE__), "lib", "awesome_print") diff --git a/lib/ap.rb b/lib/ap.rb deleted file mode 100644 index 793a9afa..00000000 --- a/lib/ap.rb +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -# -# Keeping this for backwards compatibility to allow -# require "ap" -# -require File.dirname(__FILE__) + "/awesome_print" diff --git a/lib/awesome_print.rb b/lib/awesome_print.rb index ab4a6699..5f6d3f21 100644 --- a/lib/awesome_print.rb +++ b/lib/awesome_print.rb @@ -1,40 +1,25 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ # # AwesomePrint might be loaded implicitly through ~/.irbrc or ~/.pryrc # so do nothing for subsequent requires. # unless defined?(AwesomePrint::Inspector) %w(array string method object class kernel).each do |file| - require File.dirname(__FILE__) + "/awesome_print/core_ext/#{file}" + require "awesome_print/core_ext/#{file}" end - require File.dirname(__FILE__) + "/awesome_print/inspector" - require File.dirname(__FILE__) + "/awesome_print/formatter" - require File.dirname(__FILE__) + "/awesome_print/version" - require File.dirname(__FILE__) + "/awesome_print/core_ext/logger" if defined?(Logger) - # - # Load the following under normal circumstances as well as in Rails - # console when required from ~/.irbrc or ~/.pryrc. - # - require File.dirname(__FILE__) + "/awesome_print/ext/active_record" if defined?(ActiveRecord) || AwesomePrint.rails_console? - require File.dirname(__FILE__) + "/awesome_print/ext/active_support" if defined?(ActiveSupport) || AwesomePrint.rails_console? + require 'awesome_print/support' + require 'awesome_print/configuration' + require 'awesome_print/inspector' + require 'awesome_print/formatter' + require 'awesome_print/version' + require 'awesome_print/core_ext/logger' if defined?(Logger) + # # Load remaining extensions. # if defined?(ActiveSupport) ActiveSupport.on_load(:action_view) do - require File.dirname(__FILE__) + "/awesome_print/ext/action_view" + require 'awesome_print/ext/action_view' end end - require File.dirname(__FILE__) + "/awesome_print/ext/mongo_mapper" if defined?(MongoMapper) - require File.dirname(__FILE__) + "/awesome_print/ext/mongoid" if defined?(Mongoid) - require File.dirname(__FILE__) + "/awesome_print/ext/nokogiri" if defined?(Nokogiri) - require File.dirname(__FILE__) + "/awesome_print/ext/nobrainer" if defined?(NoBrainer) - require File.dirname(__FILE__) + "/awesome_print/ext/ripple" if defined?(Ripple) - require File.dirname(__FILE__) + "/awesome_print/ext/sequel" if defined?(Sequel) - require File.dirname(__FILE__) + "/awesome_print/ext/ostruct" if defined?(OpenStruct) end diff --git a/lib/awesome_print/configuration.rb b/lib/awesome_print/configuration.rb new file mode 100644 index 00000000..6c530aac --- /dev/null +++ b/lib/awesome_print/configuration.rb @@ -0,0 +1,44 @@ +module AwesomePrint + + class << self # Class accessors for custom defaults. + attr_accessor :defaults, :force_colors + + # Class accessor to force colorized output (ex. forked subprocess where TERM + # might be dumb). + #------------------------------------------------------------------------------ + def force_colors!(value = true) + @force_colors = value + end + + def console? + !!(defined?(IRB) || defined?(Pry)) + end + + def rails_console? + console? && !!(defined?(Rails::Console) || ENV["RAILS_ENV"]) + end + + def irb! + return unless defined?(IRB) + unless IRB.version.include?("DietRB") + IRB::Irb.class_eval do + def output_value + ap @context.last_value + end + end + else # MacRuby + IRB.formatter = Class.new(IRB::Formatter) do + def inspect_object(object) + object.ai + end + end.new + end + end + + def pry! + if defined?(Pry) + Pry.print = proc { |output, value| output.puts value.ai } + end + end + end +end diff --git a/lib/awesome_print/core_ext/array.rb b/lib/awesome_print/core_ext/array.rb index ec1a1cda..2aa9b72d 100644 --- a/lib/awesome_print/core_ext/array.rb +++ b/lib/awesome_print/core_ext/array.rb @@ -1,8 +1,3 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ # # The following makes it possible to invoke awesome_print while performing # operations on method arrays, ex: diff --git a/lib/awesome_print/core_ext/class.rb b/lib/awesome_print/core_ext/class.rb index 5faac7e8..48d09593 100644 --- a/lib/awesome_print/core_ext/class.rb +++ b/lib/awesome_print/core_ext/class.rb @@ -1,8 +1,3 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ class Class #:nodoc: # # Intercept methods below to inject @__awesome_print__ instance variable diff --git a/lib/awesome_print/core_ext/kernel.rb b/lib/awesome_print/core_ext/kernel.rb index a87d19c8..bb87daa7 100644 --- a/lib/awesome_print/core_ext/kernel.rb +++ b/lib/awesome_print/core_ext/kernel.rb @@ -1,8 +1,3 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ module Kernel def ai(options = {}) diff --git a/lib/awesome_print/core_ext/logger.rb b/lib/awesome_print/core_ext/logger.rb index 516609c3..05809a1c 100644 --- a/lib/awesome_print/core_ext/logger.rb +++ b/lib/awesome_print/core_ext/logger.rb @@ -1,8 +1,3 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ module AwesomePrint module Logger diff --git a/lib/awesome_print/core_ext/method.rb b/lib/awesome_print/core_ext/method.rb index a30b1487..f997e107 100644 --- a/lib/awesome_print/core_ext/method.rb +++ b/lib/awesome_print/core_ext/method.rb @@ -1,8 +1,3 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ # # Method#name was intorduced in Ruby 1.8.7 so we define it here as necessary. # diff --git a/lib/awesome_print/core_ext/object.rb b/lib/awesome_print/core_ext/object.rb index c58e2795..3f9dc5d0 100644 --- a/lib/awesome_print/core_ext/object.rb +++ b/lib/awesome_print/core_ext/object.rb @@ -1,8 +1,3 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ class Object #:nodoc: # # Intercept methods below to inject @__awesome_print__ instance variable diff --git a/lib/awesome_print/core_ext/string.rb b/lib/awesome_print/core_ext/string.rb index 3fa1ed9d..ad727925 100644 --- a/lib/awesome_print/core_ext/string.rb +++ b/lib/awesome_print/core_ext/string.rb @@ -1,8 +1,3 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ class String # # ANSI color codes: diff --git a/lib/awesome_print/ext/action_view.rb b/lib/awesome_print/ext/action_view.rb index c34e8d05..19a0a146 100644 --- a/lib/awesome_print/ext/action_view.rb +++ b/lib/awesome_print/ext/action_view.rb @@ -1,8 +1,3 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ module AwesomePrint module ActionView diff --git a/lib/awesome_print/ext/active_record.rb b/lib/awesome_print/ext/active_record.rb deleted file mode 100644 index e04f9fe5..00000000 --- a/lib/awesome_print/ext/active_record.rb +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module ActiveRecord - - def self.included(base) - base.send :alias_method, :cast_without_active_record, :cast - base.send :alias_method, :cast, :cast_with_active_record - end - - # Add ActiveRecord class names to the dispatcher pipeline. - #------------------------------------------------------------------------------ - def cast_with_active_record(object, type) - cast = cast_without_active_record(object, type) - return cast if !defined?(::ActiveRecord) - - if object.is_a?(::ActiveRecord::Base) - cast = :active_record_instance - elsif object.is_a?(Class) && object.ancestors.include?(::ActiveRecord::Base) - cast = :active_record_class - elsif type == :activerecord_relation || object.class.ancestors.include?(::ActiveRecord::Relation) - cast = :array - end - cast - end - - private - - # Format ActiveRecord instance object. - # - # NOTE: by default only instance attributes (i.e. columns) are shown. To format - # ActiveRecord instance as regular object showing its instance variables and - # accessors use :raw => true option: - # - # ap record, :raw => true - # - #------------------------------------------------------------------------------ - def awesome_active_record_instance(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) - return awesome_object(object) if @options[:raw] - - data = object.class.column_names.inject(::ActiveSupport::OrderedHash.new) do |hash, name| - if object.has_attribute?(name) || object.new_record? - value = object.respond_to?(name) ? object.send(name) : object.read_attribute(name) - hash[name.to_sym] = value - end - hash - end - "#{object} " << awesome_hash(data) - end - - # Format ActiveRecord class object. - #------------------------------------------------------------------------------ - def awesome_active_record_class(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) || !object.respond_to?(:columns) || object.to_s == "ActiveRecord::Base" - return awesome_class(object) if object.respond_to?(:abstract_class?) && object.abstract_class? - - data = object.columns.inject(::ActiveSupport::OrderedHash.new) do |hash, c| - hash[c.name.to_sym] = c.type - hash - end - "class #{object} < #{object.superclass} " << awesome_hash(data) - end - end -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::ActiveRecord) diff --git a/lib/awesome_print/ext/active_support.rb b/lib/awesome_print/ext/active_support.rb deleted file mode 100644 index 2774990d..00000000 --- a/lib/awesome_print/ext/active_support.rb +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module ActiveSupport - - def self.included(base) - base.send :alias_method, :cast_without_active_support, :cast - base.send :alias_method, :cast, :cast_with_active_support - end - - def cast_with_active_support(object, type) - cast = cast_without_active_support(object, type) - if defined?(::ActiveSupport) && defined?(::HashWithIndifferentAccess) - if (defined?(::ActiveSupport::TimeWithZone) && object.is_a?(::ActiveSupport::TimeWithZone)) || object.is_a?(::Date) - cast = :active_support_time - elsif object.is_a?(::HashWithIndifferentAccess) - cast = :hash_with_indifferent_access - end - end - cast - end - - # Format ActiveSupport::TimeWithZone as standard Time. - #------------------------------------------------------------------------------ - def awesome_active_support_time(object) - colorize(object.inspect, :time) - end - - # Format HashWithIndifferentAccess as standard Hash. - #------------------------------------------------------------------------------ - def awesome_hash_with_indifferent_access(object) - awesome_hash(object) - end - end -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::ActiveSupport) -# -# Colorize Rails logs. -# -if defined?(ActiveSupport::LogSubscriber) - AwesomePrint.force_colors! ActiveSupport::LogSubscriber.colorize_logging -end - diff --git a/lib/awesome_print/ext/mongo_mapper.rb b/lib/awesome_print/ext/mongo_mapper.rb deleted file mode 100644 index 4e7a81a9..00000000 --- a/lib/awesome_print/ext/mongo_mapper.rb +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module MongoMapper - - def self.included(base) - base.send :alias_method, :cast_without_mongo_mapper, :cast - base.send :alias_method, :cast, :cast_with_mongo_mapper - end - - # Add MongoMapper class names to the dispatcher pipeline. - #------------------------------------------------------------------------------ - def cast_with_mongo_mapper(object, type) - apply_default_mongo_mapper_options - cast = cast_without_mongo_mapper(object, type) - - if defined?(::MongoMapper::Document) - if object.is_a?(Class) && (object.ancestors & [ ::MongoMapper::Document, ::MongoMapper::EmbeddedDocument ]).size > 0 - cast = :mongo_mapper_class - elsif object.is_a?(::MongoMapper::Document) || object.is_a?(::MongoMapper::EmbeddedDocument) - cast = :mongo_mapper_instance - elsif object.is_a?(::MongoMapper::Plugins::Associations::Base) - cast = :mongo_mapper_association - elsif object.is_a?(::BSON::ObjectId) - cast = :mongo_mapper_bson_id - end - end - - cast - end - - # Format MongoMapper class object. - #------------------------------------------------------------------------------ - def awesome_mongo_mapper_class(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) || !object.respond_to?(:keys) - - data = object.keys.sort.inject(::ActiveSupport::OrderedHash.new) do |hash, c| - hash[c.first] = (c.last.type || "undefined").to_s.underscore.intern - hash - end - - # Add in associations - if @options[:mongo_mapper][:show_associations] - object.associations.each do |name, assoc| - data[name.to_s] = assoc - end - end - - "class #{object} < #{object.superclass} " << awesome_hash(data) - end - - # Format MongoMapper instance object. - # - # NOTE: by default only instance attributes (i.e. keys) are shown. To format - # MongoMapper instance as regular object showing its instance variables and - # accessors use :raw => true option: - # - # ap record, :raw => true - # - #------------------------------------------------------------------------------ - def awesome_mongo_mapper_instance(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) - return awesome_object(object) if @options[:raw] - - data = object.keys.keys.sort_by{|k| k}.inject(::ActiveSupport::OrderedHash.new) do |hash, name| - hash[name] = object[name] - hash - end - - # Add in associations - if @options[:mongo_mapper][:show_associations] - object.associations.each do |name, assoc| - if @options[:mongo_mapper][:inline_embedded] and assoc.embeddable? - data[name.to_s] = object.send(name) - else - data[name.to_s] = assoc - end - end - end - - label = object.to_s - label = "#{colorize('embedded', :assoc)} #{label}" if object.is_a?(::MongoMapper::EmbeddedDocument) - - "#{label} " << awesome_hash(data) - end - - # Format MongoMapper association object. - #------------------------------------------------------------------------------ - def awesome_mongo_mapper_association(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) - return awesome_object(object) if @options[:raw] - - association = object.class.name.split('::').last.titleize.downcase.sub(/ association$/,'') - association = "embeds #{association}" if object.embeddable? - class_name = object.class_name - - "#{colorize(association, :assoc)} #{colorize(class_name, :class)}" - end - - # Format BSON::ObjectId - #------------------------------------------------------------------------------ - def awesome_mongo_mapper_bson_id(object) - object.inspect - end - - private - - def apply_default_mongo_mapper_options - @options[:color][:assoc] ||= :greenish - @options[:mongo_mapper] ||= { - :show_associations => false, # Display association data for MongoMapper documents and classes. - :inline_embedded => false # Display embedded associations inline with MongoMapper documents. - } - end - end -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::MongoMapper) diff --git a/lib/awesome_print/ext/mongoid.rb b/lib/awesome_print/ext/mongoid.rb deleted file mode 100644 index 6d4d1030..00000000 --- a/lib/awesome_print/ext/mongoid.rb +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module Mongoid - - def self.included(base) - base.send :alias_method, :cast_without_mongoid, :cast - base.send :alias_method, :cast, :cast_with_mongoid - end - - # Add Mongoid class names to the dispatcher pipeline. - #------------------------------------------------------------------------------ - def cast_with_mongoid(object, type) - cast = cast_without_mongoid(object, type) - if defined?(::Mongoid::Document) - if object.is_a?(Class) && object.ancestors.include?(::Mongoid::Document) - cast = :mongoid_class - elsif object.class.ancestors.include?(::Mongoid::Document) - cast = :mongoid_document - elsif (defined?(::BSON) && object.is_a?(::BSON::ObjectId)) || (defined?(::Moped::BSON) && object.is_a?(::Moped::BSON::ObjectId)) - cast = :mongoid_bson_id - end - end - cast - end - - # Format Mongoid class object. - #------------------------------------------------------------------------------ - def awesome_mongoid_class(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) || !object.respond_to?(:fields) - - data = object.fields.sort_by { |key| key }.inject(::ActiveSupport::OrderedHash.new) do |hash, c| - hash[c[1].name.to_sym] = (c[1].type || "undefined").to_s.underscore.intern - hash - end - "class #{object} < #{object.superclass} " << awesome_hash(data) - end - - # Format Mongoid Document object. - #------------------------------------------------------------------------------ - def awesome_mongoid_document(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) - - data = (object.attributes || {}).sort_by { |key| key }.inject(::ActiveSupport::OrderedHash.new) do |hash, c| - hash[c[0].to_sym] = c[1] - hash - end - if !object.errors.empty? - data = {:errors => object.errors, :attributes => data} - end - "#{object} #{awesome_hash(data)}" - end - - # Format BSON::ObjectId - #------------------------------------------------------------------------------ - def awesome_mongoid_bson_id(object) - object.inspect - end - end -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::Mongoid) diff --git a/lib/awesome_print/ext/nobrainer.rb b/lib/awesome_print/ext/nobrainer.rb deleted file mode 100644 index d13b9068..00000000 --- a/lib/awesome_print/ext/nobrainer.rb +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module NoBrainer - - def self.included(base) - base.send :alias_method, :cast_without_nobrainer, :cast - base.send :alias_method, :cast, :cast_with_nobrainer - end - - # Add NoBrainer class names to the dispatcher pipeline. - #------------------------------------------------------------------------------ - def cast_with_nobrainer(object, type) - cast = cast_without_nobrainer(object, type) - if defined?(::NoBrainer::Document) - if object.is_a?(Class) && object < ::NoBrainer::Document - cast = :nobrainer_class - elsif object.is_a?(::NoBrainer::Document) - cast = :nobrainer_document - end - end - cast - end - - # Format NoBrainer class object. - #------------------------------------------------------------------------------ - def awesome_nobrainer_class(object) - data = Hash[object.fields.map do |field, options| - [field, (options[:type] || Object).to_s.underscore.to_sym] - end] - "class #{object} < #{object.superclass} " << awesome_hash(data) - end - - # Format NoBrainer Document object. - #------------------------------------------------------------------------------ - def awesome_nobrainer_document(object) - data = object.inspectable_attributes.symbolize_keys - if object.errors.present? - data = {:errors => object.errors, :attributes => data} - end - "#{object} #{awesome_hash(data)}" - end - end -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::NoBrainer) diff --git a/lib/awesome_print/ext/nokogiri.rb b/lib/awesome_print/ext/nokogiri.rb deleted file mode 100644 index 4d26c92d..00000000 --- a/lib/awesome_print/ext/nokogiri.rb +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module Nokogiri - - def self.included(base) - base.send :alias_method, :cast_without_nokogiri, :cast - base.send :alias_method, :cast, :cast_with_nokogiri - end - - # Add Nokogiri XML Node and NodeSet names to the dispatcher pipeline. - #------------------------------------------------------------------------------ - def cast_with_nokogiri(object, type) - cast = cast_without_nokogiri(object, type) - if (defined?(::Nokogiri::XML::Node) && object.is_a?(::Nokogiri::XML::Node)) || - (defined?(::Nokogiri::XML::NodeSet) && object.is_a?(::Nokogiri::XML::NodeSet)) - cast = :nokogiri_xml_node - end - cast - end - - #------------------------------------------------------------------------------ - def awesome_nokogiri_xml_node(object) - if object.is_a?(::Nokogiri::XML::NodeSet) && object.empty? - return "[]" - end - xml = object.to_xml(:indent => 2) - # - # Colorize tag, id/class name, and contents. - # - xml.gsub!(/(<)(\/?[A-Za-z1-9]+)/) { |tag| "#{$1}#{colorize($2, :keyword)}" } - xml.gsub!(/(id|class)="[^"]+"/i) { |id| colorize(id, :class) } - xml.gsub!(/>([^<]+)#{contents}<" - end - xml - end - end -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::Nokogiri) diff --git a/lib/awesome_print/ext/ostruct.rb b/lib/awesome_print/ext/ostruct.rb deleted file mode 100644 index 199122f8..00000000 --- a/lib/awesome_print/ext/ostruct.rb +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module OpenStruct - def self.included(base) - base.send :alias_method, :cast_without_ostruct, :cast - base.send :alias_method, :cast, :cast_with_ostruct - end - - def cast_with_ostruct(object, type) - cast = cast_without_ostruct(object, type) - if (defined?(::OpenStruct)) && (object.is_a?(::OpenStruct)) - cast = :open_struct_instance - end - cast - end - - def awesome_open_struct_instance(object) - "#{object.class} #{awesome_hash(object.marshal_dump)}" - end - end -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::OpenStruct) diff --git a/lib/awesome_print/ext/ripple.rb b/lib/awesome_print/ext/ripple.rb deleted file mode 100644 index 7bd6facf..00000000 --- a/lib/awesome_print/ext/ripple.rb +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module Ripple - - def self.included(base) - base.send :alias_method, :cast_without_ripple, :cast - base.send :alias_method, :cast, :cast_with_ripple - end - - # Add Ripple class names to the dispatcher pipeline. - #------------------------------------------------------------------------------ - def cast_with_ripple(object, type) - cast = cast_without_ripple(object, type) - return cast if !defined?(::Ripple) - - if object.is_a?(::Ripple::AttributeMethods) # Module used to access attributes across documents and embedded documents - cast = :ripple_document_instance - elsif object.is_a?(::Ripple::Properties) # Used to access property metadata on Ripple classes - cast = :ripple_document_class - end - cast - end - - private - - # Format Ripple instance object. - # - # NOTE: by default only instance attributes are shown. To format a Ripple document instance - # as a regular object showing its instance variables and accessors use :raw => true option: - # - # ap document, :raw => true - # - #------------------------------------------------------------------------------ - def awesome_ripple_document_instance(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) - return awesome_object(object) if @options[:raw] - exclude_assoc = @options[:exclude_assoc] or @options[:exclude_associations] - - data = object.attributes.inject(::ActiveSupport::OrderedHash.new) do |hash, (name, value)| - hash[name.to_sym] = object.send(name) - hash - end - - unless exclude_assoc - data = object.class.embedded_associations.inject(data) do |hash, assoc| - hash[assoc.name] = object.get_proxy(assoc) # Should always be array or Ripple::EmbeddedDocument for embedded associations - hash - end - end - - "#{object} " << awesome_hash(data) - end - - # Format Ripple class object. - #------------------------------------------------------------------------------ - def awesome_ripple_document_class(object) - return object.inspect if !defined?(::ActiveSupport::OrderedHash) || !object.respond_to?(:properties) - - data = object.properties.inject(::ActiveSupport::OrderedHash.new) do |hash, (name, defn)| - hash[name.to_sym] = defn.type.to_s.downcase.to_sym - hash - end - "class #{object} < #{object.superclass} " << awesome_hash(data) - end - end -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::Ripple) diff --git a/lib/awesome_print/ext/sequel.rb b/lib/awesome_print/ext/sequel.rb deleted file mode 100644 index 75cfa23e..00000000 --- a/lib/awesome_print/ext/sequel.rb +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -module AwesomePrint - module Sequel - - def self.included(base) - base.send :alias_method, :cast_without_sequel, :cast - base.send :alias_method, :cast, :cast_with_sequel - end - - # Add Sequel class names to the dispatcher pipeline. - #------------------------------------------------------------------------------ - def cast_with_sequel(object, type) - cast = cast_without_sequel(object, type) - if defined?(::Sequel::Model) && object.is_a?(::Sequel::Model) - cast = :sequel_document - elsif defined?(::Sequel::Model) && object.is_a?(Class) && object.ancestors.include?(::Sequel::Model) - cast = :sequel_model_class - elsif defined?(::Sequel::Mysql2::Dataset) && object.class.ancestors.include?(::Sequel::Mysql2::Dataset) - cast = :sequel_dataset - end - cast - end - - # Format Sequel Document object. - #------------------------------------------------------------------------------ - def awesome_sequel_document(object) - data = object.values.sort_by { |key| key.to_s }.inject({}) do |hash, c| - hash[c[0].to_sym] = c[1] - hash - end - if !object.errors.empty? - data = {:errors => object.errors, :values => data} - end - "#{object} #{awesome_hash(data)}" - end - - # Format Sequel Dataset object. - #------------------------------------------------------------------------------ - def awesome_sequel_dataset(dataset) - [awesome_array(dataset.to_a), awesome_print(dataset.sql)].join("\n") - end - - # Format Sequel Model class. - #------------------------------------------------------------------------------ - def awesome_sequel_model_class(object) - data = object.db_schema.inject({}) {|h, (name,data)| h.merge(name => data[:db_type])} - "class #{object} < #{object.superclass} " << awesome_hash(data) - end - end - -end - -AwesomePrint::Formatter.send(:include, AwesomePrint::Sequel) diff --git a/lib/awesome_print/formatter.rb b/lib/awesome_print/formatter.rb index 0e07ecbb..c464017a 100644 --- a/lib/awesome_print/formatter.rb +++ b/lib/awesome_print/formatter.rb @@ -1,16 +1,12 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -autoload :CGI, "cgi" -require "shellwords" +autoload :CGI, 'cgi' +require 'shellwords' +require 'awesome_print/formatter_factory' +require 'awesome_print/type_discover' module AwesomePrint class Formatter - CORE = [ :array, :bigdecimal, :class, :dir, :file, :hash, :method, :rational, :set, :struct, :unboundmethod ] - DEFAULT_LIMIT_SIZE = 7 + attr_reader :options, :inspector, :indentation, :type, :object def initialize(inspector) @inspector = inspector @@ -20,21 +16,10 @@ def initialize(inspector) # Main entry point to format an object. #------------------------------------------------------------------------------ - def format(object, type = nil) - core_class = cast(object, type) - awesome = if core_class != :self - send(:"awesome_#{core_class}", object) # Core formatters. - else - awesome_self(object, type) # Catch all that falls back to object.inspect. - end - awesome - end - - # Hook this when adding custom formatters. Check out lib/awesome_print/ext - # directory for custom formatters that ship with awesome_print. - #------------------------------------------------------------------------------ - def cast(object, type) - CORE.grep(type)[0] || :self + def format(object) + @type = printable(object) + @object = object + AwesomePrint::FormatterFactory.from(self, object) end # Pick the color and apply it to the given string as necessary. @@ -55,283 +40,19 @@ def colorize(str, type) end end - - private - - # Catch all method to format an arbitrary object. - #------------------------------------------------------------------------------ - def awesome_self(object, type) - if @options[:raw] && object.instance_variables.any? - return awesome_object(object) - elsif hash = convert_to_hash(object) - awesome_hash(hash) - else - colorize(object.inspect.to_s, type) - end - end - - # Format an array. - #------------------------------------------------------------------------------ - def awesome_array(a) - return "[]" if a == [] - - if a.instance_variable_defined?('@__awesome_methods__') - methods_array(a) - elsif @options[:multiline] - width = (a.size - 1).to_s.size - - data = a.inject([]) do |arr, item| - index = indent - index << colorize("[#{arr.size.to_s.rjust(width)}] ", :array) if @options[:index] - indented do - arr << (index << @inspector.awesome(item)) - end - end - - data = limited(data, width) if should_be_limited? - "[\n" << data.join(",\n") << "\n#{outdent}]" - else - "[ " << a.map{ |item| @inspector.awesome(item) }.join(", ") << " ]" - end - end - - # Format a hash. If @options[:indent] if negative left align hash keys. - #------------------------------------------------------------------------------ - def awesome_hash(h) - return "{}" if h == {} - - keys = @options[:sort_keys] ? h.keys.sort { |a, b| a.to_s <=> b.to_s } : h.keys - data = keys.map do |key| - plain_single_line do - [ @inspector.awesome(key), h[key] ] - end - end - - width = data.map { |key, | key.size }.max || 0 - width += @indentation if @options[:indent] > 0 - - data = data.map do |key, value| - indented do - align(key, width) << colorize(" => ", :hash) << @inspector.awesome(value) - end - end - - data = limited(data, width, :hash => true) if should_be_limited? - if @options[:multiline] - "{\n" << data.join(",\n") << "\n#{outdent}}" - else - "{ #{data.join(', ')} }" - end - end - - # Format an object. - #------------------------------------------------------------------------------ - def awesome_object(o) - vars = o.instance_variables.map do |var| - property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet. - accessor = if o.respond_to?(:"#{property}=") - o.respond_to?(property) ? :accessor : :writer - else - o.respond_to?(property) ? :reader : nil - end - if accessor - [ "attr_#{accessor} :#{property}", var ] - else - [ var.to_s, var ] - end - end - - data = vars.sort.map do |declaration, var| - key = left_aligned do - align(declaration, declaration.size) - end - - unless @options[:plain] - if key =~ /(@\w+)/ - key.sub!($1, colorize($1, :variable)) - else - key.sub!(/(attr_\w+)\s(\:\w+)/, "#{colorize('\\1', :keyword)} #{colorize('\\2', :method)}") - end - end - indented do - key << colorize(" = ", :hash) + @inspector.awesome(o.instance_variable_get(var)) - end - end - if @options[:multiline] - "#<#{awesome_instance(o)}\n#{data.join(%Q/,\n/)}\n#{outdent}>" - else - "#<#{awesome_instance(o)} #{data.join(', ')}>" - end - end - - # Format a set. - #------------------------------------------------------------------------------ - def awesome_set(s) - awesome_array(s.to_a) - end - - # Format a Struct. - #------------------------------------------------------------------------------ - def awesome_struct(s) - # - # The code is slightly uglier because of Ruby 1.8.6 quirks: - # awesome_hash(Hash[s.members.zip(s.values)]) <-- ArgumentError: odd number of arguments for Hash) - # awesome_hash(Hash[*s.members.zip(s.values).flatten]) <-- s.members returns strings, not symbols. - # - hash = {} - s.each_pair { |key, value| hash[key] = value } - awesome_hash(hash) - end - - # Format Class object. - #------------------------------------------------------------------------------ - def awesome_class(c) - if superclass = c.superclass # <-- Assign and test if nil. - colorize("#{c.inspect} < #{superclass}", :class) - else - colorize(c.inspect, :class) - end - end - - # Format File object. - #------------------------------------------------------------------------------ - def awesome_file(f) - ls = File.directory?(f) ? `ls -adlF #{f.path.shellescape}` : `ls -alF #{f.path.shellescape}` - colorize(ls.empty? ? f.inspect : "#{f.inspect}\n#{ls.chop}", :file) - end - - # Format Dir object. - #------------------------------------------------------------------------------ - def awesome_dir(d) - ls = `ls -alF #{d.path.shellescape}` - colorize(ls.empty? ? d.inspect : "#{d.inspect}\n#{ls.chop}", :dir) - end - - # Format BigDecimal object. - #------------------------------------------------------------------------------ - def awesome_bigdecimal(n) - colorize(n.to_s("F"), :bigdecimal) - end - - # Format Rational object. - #------------------------------------------------------------------------------ - def awesome_rational(n) - colorize(n.to_s, :rational) - end - - # Format a method. - #------------------------------------------------------------------------------ - def awesome_method(m) - name, args, owner = method_tuple(m) - "#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}" - end - alias :awesome_unboundmethod :awesome_method - - # Format object instance. - #------------------------------------------------------------------------------ - def awesome_instance(o) - "#{o.class}:0x%08x" % (o.__id__ * 2) - end - - # Format object.methods array. - #------------------------------------------------------------------------------ - def methods_array(a) - a.sort! { |x, y| x.to_s <=> y.to_s } # Can't simply a.sort! because of o.methods << [ :blah ] - object = a.instance_variable_get('@__awesome_methods__') - tuples = a.map do |name| - if name.is_a?(Symbol) || name.is_a?(String) # Ignore garbage, ex. 42.methods << [ :blah ] - tuple = if object.respond_to?(name, true) # Is this a regular method? - the_method = object.method(name) rescue nil # Avoid potential ArgumentError if object#method is overridden. - if the_method && the_method.respond_to?(:arity) # Is this original object#method? - method_tuple(the_method) # Yes, we are good. - end - elsif object.respond_to?(:instance_method) # Is this an unbound method? - method_tuple(object.instance_method(name)) rescue nil # Rescue to avoid NameError when the method is not - end # available (ex. File.lchmod on Ubuntu 12). - end - tuple || [ name.to_s, '(?)', '?' ] # Return WTF default if all the above fails. - end - - width = (tuples.size - 1).to_s.size - name_width = tuples.map { |item| item[0].size }.max || 0 - args_width = tuples.map { |item| item[1].size }.max || 0 - - data = tuples.inject([]) do |arr, item| - index = indent - index << "[#{arr.size.to_s.rjust(width)}]" if @options[:index] - indented do - arr << "#{index} #{colorize(item[0].rjust(name_width), :method)}#{colorize(item[1].ljust(args_width), :args)} #{colorize(item[2], :class)}" - end - end - - "[\n" << data.join("\n") << "\n#{outdent}]" + def indent + ' ' * @indentation end - # Return [ name, arguments, owner ] tuple for a given method. - #------------------------------------------------------------------------------ - def method_tuple(method) - if method.respond_to?(:parameters) # Ruby 1.9.2+ - # See http://ruby.runpaint.org/methods#method-objects-parameters - args = method.parameters.inject([]) do |arr, (type, name)| - name ||= (type == :block ? 'block' : "arg#{arr.size + 1}") - arr << case type - when :req then name.to_s - when :opt, :rest then "*#{name}" - when :block then "&#{name}" - else '?' - end - end - else # See http://ruby-doc.org/core/classes/Method.html#M001902 - args = (1..method.arity.abs).map { |i| "arg#{i}" } - args[-1] = "*#{args[-1]}" if method.arity < 0 - end - - # method.to_s formats to handle: - # - # # - # # - # #)#_username> - # # - # # - # # - # - if method.to_s =~ /(Unbound)*Method: (.*)[#\.]/ - unbound, klass = $1 && '(unbound)', $2 - if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class? - klass.sub!($1, '') # Yes, strip the fields leaving class name only. - end - owner = "#{klass}#{unbound}".gsub('(', ' (') - end - - [ method.name.to_s, "(#{args.join(', ')})", owner.to_s ] + def outdent + ' ' * (@indentation - @options[:indent].abs) end - # Format hash keys as plain strings regardless of underlying data type. - #------------------------------------------------------------------------------ - def plain_single_line - plain, multiline = @options[:plain], @options[:multiline] - @options[:plain], @options[:multiline] = true, false + def indented + @indentation += @options[:indent].abs yield ensure - @options[:plain], @options[:multiline] = plain, multiline - end - - # Utility methods. - #------------------------------------------------------------------------------ - def convert_to_hash(object) - if ! object.respond_to?(:to_hash) - return nil - end - if object.method(:to_hash).arity != 0 - return nil - end - - hash = object.to_hash - if ! hash.respond_to?(:keys) || ! hash.respond_to?('[]') - return nil - end - - return hash + @indentation -= @options[:indent].abs end def align(value, width) @@ -348,13 +69,6 @@ def align(value, width) end end - def indented - @indentation += @options[:indent].abs - yield - ensure - @indentation -= @options[:indent].abs - end - def left_aligned current, @options[:indent] = @options[:indent], 0 yield @@ -362,61 +76,37 @@ def left_aligned @options[:indent] = current end - def indent - ' ' * @indentation - end - - def outdent - ' ' * (@indentation - @options[:indent].abs) - end - - # To support limited output, for example: - # - # ap ('a'..'z').to_a, :limit => 3 - # [ - # [ 0] "a", - # [ 1] .. [24], - # [25] "z" - # ] - # - # ap (1..100).to_a, :limit => true # Default limit is 7. - # [ - # [ 0] 1, - # [ 1] 2, - # [ 2] 3, - # [ 3] .. [96], - # [97] 98, - # [98] 99, - # [99] 100 - # ] + # Format nested data, for example: + # arr = [1, 2]; arr << arr + # => [1,2, [...]] + # hash = { :a => 1 }; hash[:b] = hash + # => { :a => 1, :b => {...} } #------------------------------------------------------------------------------ - def should_be_limited? - @options[:limit] == true or (@options[:limit].is_a?(Fixnum) and @options[:limit] > 0) + def nested(object) + case printable(object) + when :array then colorize("[...]", :array) + when :hash then colorize("{...}", :hash) + when :struct then colorize("{...}", :struct) + else colorize("...#{object.class}...", :class) + end end - def get_limit_size - @options[:limit] == true ? DEFAULT_LIMIT_SIZE : @options[:limit] + #------------------------------------------------------------------------------ + def unnested(object) + format(object) end - def limited(data, width, is_hash = false) - limit = get_limit_size - if data.length <= limit - data - else - # Calculate how many elements to be displayed above and below the separator. - head = limit / 2 - tail = head - (limit - 1) % 2 - - # Add the proper elements to the temp array and format the separator. - temp = data[0, head] + [ nil ] + data[-tail, tail] - - if is_hash - temp[head] = "#{indent}#{data[head].strip} .. #{data[data.length - tail - 1].strip}" - else - temp[head] = "#{indent}[#{head.to_s.rjust(width)}] .. [#{data.length - tail - 1}]" - end - - temp + # Turn class name into symbol, ex: Hello::World => :hello_world. Classes that + # inherit from Array, Hash, File, Dir, and Struct are treated as the base class. + #------------------------------------------------------------------------------ + def printable(object) + case object + when Array then :array + when Hash then :hash + when File then :file + when Dir then :dir + when Struct then :struct + else object.class.to_s.gsub(/:+/, "_").downcase.to_sym end end end diff --git a/lib/awesome_print/formatter_factory.rb b/lib/awesome_print/formatter_factory.rb new file mode 100644 index 00000000..0fc22146 --- /dev/null +++ b/lib/awesome_print/formatter_factory.rb @@ -0,0 +1,26 @@ +require 'awesome_print/formatters' + +module AwesomePrint + class FormatterFactory + + def self.from(formatter, object) + new(formatter, object).call + end + + def initialize(formatter, object) + @type = AwesomePrint::TypeDiscover.new(formatter).call + @class_name = @type.to_s.split('_').map(&:capitalize).join('') + @formatter = formatter + @object = object + end + + def call + klass = AwesomePrint::Support.constantize("AwesomePrint::Formatters::#{class_name}") + klass.new(formatter, object).call + end + + private + + attr_reader :class_name, :formatter, :object + end +end diff --git a/lib/awesome_print/formatters.rb b/lib/awesome_print/formatters.rb new file mode 100644 index 00000000..5e0b85e4 --- /dev/null +++ b/lib/awesome_print/formatters.rb @@ -0,0 +1,38 @@ +module AwesomePrint + module Formatters + require 'awesome_print/formatters/formatter' + require 'awesome_print/formatters/self' + require 'awesome_print/formatters/array' + require 'awesome_print/formatters/hash' + require 'awesome_print/formatters/object' + require 'awesome_print/formatters/set' + require 'awesome_print/formatters/struct' + require 'awesome_print/formatters/class' + require 'awesome_print/formatters/file' + require 'awesome_print/formatters/dir' + require 'awesome_print/formatters/bigdecimal' + require 'awesome_print/formatters/rational' + require 'awesome_print/formatters/method' + require 'awesome_print/formatters/unboundmethod' + require 'awesome_print/formatters/active_record_instance' + require 'awesome_print/formatters/active_record_class' + require 'awesome_print/formatters/active_support_time' + require 'awesome_print/formatters/hash_with_indifferent_access' + require 'awesome_print/formatters/mongoid_class' + require 'awesome_print/formatters/mongoid_document' + require 'awesome_print/formatters/mongoid_bson_id' + require 'awesome_print/formatters/mongo_mapper_instance' + require 'awesome_print/formatters/mongo_mapper_class' + require 'awesome_print/formatters/mongo_mapper_association' + require 'awesome_print/formatters/mongo_mapper_bson_id' + require 'awesome_print/formatters/nobrainer_class' + require 'awesome_print/formatters/nobrainer_document' + require 'awesome_print/formatters/nokogiri_xml_node' + require 'awesome_print/formatters/open_struct_instance' + require 'awesome_print/formatters/ripple_document_instance' + require 'awesome_print/formatters/ripple_document_class' + require 'awesome_print/formatters/sequel_document' + require 'awesome_print/formatters/sequel_dataset' + require 'awesome_print/formatters/sequel_model_class' + end +end diff --git a/lib/awesome_print/formatters/active_record_class.rb b/lib/awesome_print/formatters/active_record_class.rb new file mode 100644 index 00000000..4ad5319b --- /dev/null +++ b/lib/awesome_print/formatters/active_record_class.rb @@ -0,0 +1,34 @@ +module AwesomePrint + module Formatters + class ActiveRecordClass < Formatter + + def call + return object.inspect if not_a_active_record_class? + return class_format if object_is_abstract_class? + + "class #{object} < #{object.superclass} " << AwesomePrint::Formatters::Hash.new(formatter, columns).call + end + + private + + def class_format + AwesomePrint::Formatters::Class.new(formatter, object).call + end + + def object_is_abstract_class? + object.respond_to?(:abstract_class?) && object.abstract_class? + end + + def not_a_active_record_class? + !defined?(::ActiveSupport::OrderedHash) || !object.respond_to?(:columns) || object.to_s == "ActiveRecord::Base" + end + + def columns + object.columns.inject(::ActiveSupport::OrderedHash.new) do |hash, c| + hash[c.name.to_sym] = c.type + hash + end + end + end + end +end diff --git a/lib/awesome_print/formatters/active_record_instance.rb b/lib/awesome_print/formatters/active_record_instance.rb new file mode 100644 index 00000000..45e52b7a --- /dev/null +++ b/lib/awesome_print/formatters/active_record_instance.rb @@ -0,0 +1,38 @@ +module AwesomePrint + module Formatters + class ActiveRecordInstance < Formatter + + # Format ActiveRecord instance object. + # + # NOTE: by default only instance attributes (i.e. columns) are shown. To format + # ActiveRecord instance as regular object showing its instance variables and + # accessors use :raw => true option: + # + # ap record, :raw => true + # + #------------------------------------------------------------------------------ + def call + return object.inspect if !defined?(::ActiveSupport::OrderedHash) + return raw_format if options[:raw] + + "#{object} " << AwesomePrint::Formatters::Hash.new(formatter, columns).call + end + + private + + def raw_format + AwesomePrint::Formatters::Object.new(formatter, object).call + end + + def columns + object.class.column_names.inject(::ActiveSupport::OrderedHash.new) do |hash, name| + if object.has_attribute?(name) || object.new_record? + value = object.respond_to?(name) ? object.send(name) : object.read_attribute(name) + hash[name.to_sym] = value + end + hash + end + end + end + end +end diff --git a/lib/awesome_print/formatters/active_support_time.rb b/lib/awesome_print/formatters/active_support_time.rb new file mode 100644 index 00000000..f30e5bc0 --- /dev/null +++ b/lib/awesome_print/formatters/active_support_time.rb @@ -0,0 +1,10 @@ +module AwesomePrint + module Formatters + class ActiveSupportTime < Formatter + + def call + formatter.colorize(object.inspect, :time) + end + end + end +end diff --git a/lib/awesome_print/formatters/array.rb b/lib/awesome_print/formatters/array.rb new file mode 100644 index 00000000..75062eb2 --- /dev/null +++ b/lib/awesome_print/formatters/array.rb @@ -0,0 +1,86 @@ +require 'awesome_print/formatters/enumerable' +require 'awesome_print/formatters/method_tuple' + +module AwesomePrint + module Formatters + class Array < Formatter + include Enumerable + include MethodTuple + + def call + return empty_format if object.empty? + + if object.instance_variable_defined?('@__awesome_methods__') + methods_format + elsif options[:multiline] + multiline_format + else + inline_format + end + end + + private + + def empty_format + '[]' + end + + def methods_format + methods_array(object) + end + + def inline_format + "[ " << object.map{ |item| inspector.awesome(item) }.join(", ") << " ]" + end + + def multiline_format + width = (object.size - 1).to_s.size + + data = object.inject([]) do |arr, item| + index = formatter.indent + index << formatter.colorize("[#{arr.size.to_s.rjust(width)}] ", :array) if options[:index] + formatter.indented do + arr << (index << inspector.awesome(item)) + end + end + + data = limited(data, width) if should_be_limited? + "[\n" << data.join(",\n") << "\n#{formatter.outdent}]" + end + + # Format object.methods array. + #------------------------------------------------------------------------------ + def methods_array(a) + a.sort! { |x, y| x.to_s <=> y.to_s } # Can't simply a.sort! because of o.methods << [ :blah ] + object = a.instance_variable_get('@__awesome_methods__') + tuples = a.map do |name| + if name.is_a?(Symbol) || name.is_a?(String) # Ignore garbage, ex. 42.methods << [ :blah ] + tuple = if object.respond_to?(name, true) # Is this a regular method? + the_method = object.method(name) rescue nil # Avoid potential ArgumentError if object#method is overridden. + if the_method && the_method.respond_to?(:arity) # Is this original object#method? + method_tuple(the_method) # Yes, we are good. + end + elsif object.respond_to?(:instance_method) # Is this an unbound method? + method_tuple(object.instance_method(name)) rescue nil # Rescue to avoid NameError when the method is not + end # available (ex. File.lchmod on Ubuntu 12). + end + tuple || [ name.to_s, '(?)', '?' ] # Return WTF default if all the above fails. + end + + width = (tuples.size - 1).to_s.size + name_width = tuples.map { |item| item[0].size }.max || 0 + args_width = tuples.map { |item| item[1].size }.max || 0 + + data = tuples.inject([]) do |arr, item| + index = formatter.indent + index << "[#{arr.size.to_s.rjust(width)}]" if options[:index] + formatter.indented do + arr << "#{index} #{formatter.colorize(item[0].rjust(name_width), :method)}#{formatter.colorize(item[1].ljust(args_width), :args)} #{formatter.colorize(item[2], :class)}" + end + end + + "[\n" << data.join("\n") << "\n#{formatter.outdent}]" + end + end + end +end diff --git a/lib/awesome_print/formatters/bigdecimal.rb b/lib/awesome_print/formatters/bigdecimal.rb new file mode 100644 index 00000000..feea430d --- /dev/null +++ b/lib/awesome_print/formatters/bigdecimal.rb @@ -0,0 +1,11 @@ +module AwesomePrint + module Formatters + class Bigdecimal < Formatter + + def call + formatter.colorize(object.to_s('F'), :bigdecimal) + end + end + end +end + diff --git a/lib/awesome_print/formatters/class.rb b/lib/awesome_print/formatters/class.rb new file mode 100644 index 00000000..ddc2e2ef --- /dev/null +++ b/lib/awesome_print/formatters/class.rb @@ -0,0 +1,14 @@ +module AwesomePrint + module Formatters + class Class < Formatter + + def call + if superclass = object.superclass # <-- Assign and test if nil. + formatter.colorize("#{object.inspect} < #{superclass}", :class) + else + formatter.colorize(object.inspect, :class) + end + end + end + end +end diff --git a/lib/awesome_print/formatters/dir.rb b/lib/awesome_print/formatters/dir.rb new file mode 100644 index 00000000..b9b3cd94 --- /dev/null +++ b/lib/awesome_print/formatters/dir.rb @@ -0,0 +1,11 @@ +module AwesomePrint + module Formatters + class Dir < Formatter + + def call + ls = `ls -alF #{object.path.shellescape}` + formatter.colorize(ls.empty? ? object.inspect : "#{object.inspect}\n#{ls.chop}", :dir) + end + end + end +end diff --git a/lib/awesome_print/formatters/enumerable.rb b/lib/awesome_print/formatters/enumerable.rb new file mode 100644 index 00000000..a31601ea --- /dev/null +++ b/lib/awesome_print/formatters/enumerable.rb @@ -0,0 +1,60 @@ +module AwesomePrint + module Formatters + module Enumerable + + DEFAULT_LIMIT_SIZE = 7 + + # To support limited output, for example: + # + # ap ('a'..'z').to_a, :limit => 3 + # [ + # [ 0] "a", + # [ 1] .. [24], + # [25] "z" + # ] + # + # ap (1..100).to_a, :limit => true # Default limit is 7. + # [ + # [ 0] 1, + # [ 1] 2, + # [ 2] 3, + # [ 3] .. [96], + # [97] 98, + # [98] 99, + # [99] 100 + # ] + #------------------------------------------------------------------------------ + def should_be_limited? + @options[:limit] == true or (@options[:limit].is_a?(Fixnum) and @options[:limit] > 0) + end + + # Mover para um modulo e incluir apenas no array e hash formatters + # fazer o mesmo com o should_be_limited? + def limited(data, width, is_hash = false) + limit = get_limit_size + if data.length <= limit + data + else + # Calculate how many elements to be displayed above and below the separator. + head = limit / 2 + tail = head - (limit - 1) % 2 + + # Add the proper elements to the temp array and format the separator. + temp = data[0, head] + [ nil ] + data[-tail, tail] + + if is_hash + temp[head] = "#{formatter.indent}#{data[head].strip} .. #{data[data.length - tail - 1].strip}" + else + temp[head] = "#{formatter.indent}[#{head.to_s.rjust(width)}] .. [#{data.length - tail - 1}]" + end + + temp + end + end + + def get_limit_size + options[:limit] == true ? DEFAULT_LIMIT_SIZE : options[:limit] + end + end + end +end diff --git a/lib/awesome_print/formatters/file.rb b/lib/awesome_print/formatters/file.rb new file mode 100644 index 00000000..f11ce730 --- /dev/null +++ b/lib/awesome_print/formatters/file.rb @@ -0,0 +1,11 @@ +module AwesomePrint + module Formatters + class File < Formatter + + def call + ls = ::File.directory?(object) ? `ls -adlF #{object.path.shellescape}` : `ls -alF #{object.path.shellescape}` + formatter.colorize(ls.empty? ? object.inspect : "#{object.inspect}\n#{ls.chop}", :file) + end + end + end +end diff --git a/lib/awesome_print/formatters/formatter.rb b/lib/awesome_print/formatters/formatter.rb new file mode 100644 index 00000000..cc963cec --- /dev/null +++ b/lib/awesome_print/formatters/formatter.rb @@ -0,0 +1,26 @@ +module AwesomePrint + module Formatters + class Formatter + + def initialize(formatter, object) + @formatter = formatter + @object = object + @options = formatter.options + @inspector = formatter.inspector + @indentation = formatter.indentation + end + + private + + attr_reader :formatter, :object, :indentation + + def options + @options + end + + def inspector + @inspector + end + end + end +end diff --git a/lib/awesome_print/formatters/hash.rb b/lib/awesome_print/formatters/hash.rb new file mode 100644 index 00000000..cf99d3be --- /dev/null +++ b/lib/awesome_print/formatters/hash.rb @@ -0,0 +1,87 @@ +require 'awesome_print/formatters/enumerable' + +module AwesomePrint + module Formatters + class Hash < Formatter + include Enumerable + + def call + return empty_format if object.empty? + build_data + if options[:multiline] + multiline_format + else + inline_format + end + end + + private + + attr_reader :width, :data + + def empty_format + '{}' + end + + def keys + options[:sort_keys] ? object.keys.sort { |a, b| a.to_s <=> b.to_s } : object.keys + end + + def build_width + @width = @data.map { |key, | key.size }.max || 0 + @width += indentation if options[:indent] > 0 + end + + def build_data + @data = keys.map do |key| + plain_single_line do + [ inspector.awesome(key), object[key] ] + end + end + + build_width + + @data = @data.map do |key, value| + formatter.indented do + if options[:colonize_symbol_keys] && is_a_symbol?(key) + new_hash_syntax_format(key, value) + else + old_hash_syntax_format(key, value) + end + end + end + + @data = limited(@data, width, :hash => true) if should_be_limited? + end + + def multiline_format + "{\n" << data.join(",\n") << "\n#{formatter.outdent}}" + end + + def inline_format + "{ #{data.join(', ')} }" + end + + def plain_single_line + plain, multiline = options[:plain], options[:multiline] + options[:plain], options[:multiline] = true, false + yield + ensure + options[:plain], options[:multiline] = plain, multiline + end + + def old_hash_syntax_format(key, value) + formatter.align(key, width) << formatter.colorize(" => ", :hash) << inspector.awesome(value) + end + + def new_hash_syntax_format(key, value) + key[0] = '' + formatter.align(key, width - 1) << formatter.colorize(": ", :hash) << inspector.awesome(value) + end + + def is_a_symbol?(key) + key[0] == ':' + end + end + end +end diff --git a/lib/awesome_print/formatters/hash_with_indifferent_access.rb b/lib/awesome_print/formatters/hash_with_indifferent_access.rb new file mode 100644 index 00000000..37ff5552 --- /dev/null +++ b/lib/awesome_print/formatters/hash_with_indifferent_access.rb @@ -0,0 +1,10 @@ +module AwesomePrint + module Formatters + class HashWithIndifferentAccess < Formatter + + def call + AwesomePrint::Formatters::Hash.new(formatter, object).call + end + end + end +end diff --git a/lib/awesome_print/formatters/method.rb b/lib/awesome_print/formatters/method.rb new file mode 100644 index 00000000..97c32616 --- /dev/null +++ b/lib/awesome_print/formatters/method.rb @@ -0,0 +1,14 @@ +require 'awesome_print/formatters/method_tuple' + +module AwesomePrint + module Formatters + class Method < Formatter + include MethodTuple + + def call + name, args, owner = method_tuple(object) + "#{formatter.colorize(owner, :class)}##{formatter.colorize(name, :method)}#{formatter.colorize(args, :args)}" + end + end + end +end diff --git a/lib/awesome_print/formatters/method_tuple.rb b/lib/awesome_print/formatters/method_tuple.rb new file mode 100644 index 00000000..70ca60d7 --- /dev/null +++ b/lib/awesome_print/formatters/method_tuple.rb @@ -0,0 +1,45 @@ +module AwesomePrint + module Formatters + module MethodTuple + + # Return [ name, arguments, owner ] tuple for a given method. + #------------------------------------------------------------------------------ + def method_tuple(method) + if method.respond_to?(:parameters) # Ruby 1.9.2+ + # See http://ruby.runpaint.org/methods#method-objects-parameters + args = method.parameters.inject([]) do |arr, (type, name)| + name ||= (type == :block ? 'block' : "arg#{arr.size + 1}") + arr << case type + when :req then name.to_s + when :opt, :rest then "*#{name}" + when :block then "&#{name}" + else '?' + end + end + else # See http://ruby-doc.org/core/classes/Method.html#M001902 + args = (1..method.arity.abs).map { |i| "arg#{i}" } + args[-1] = "*#{args[-1]}" if method.arity < 0 + end + + # method.to_s formats to handle: + # + # # + # # + # #)#_username> + # # + # # + # # + # + if method.to_s =~ /(Unbound)*Method: (.*)[#\.]/ + unbound, klass = $1 && '(unbound)', $2 + if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class? + klass.sub!($1, '') # Yes, strip the fields leaving class name only. + end + owner = "#{klass}#{unbound}".gsub('(', ' (') + end + + [ method.name.to_s, "(#{args.join(', ')})", owner.to_s ] + end + end + end +end diff --git a/lib/awesome_print/formatters/mongo_mapper.rb b/lib/awesome_print/formatters/mongo_mapper.rb new file mode 100644 index 00000000..1ecacd66 --- /dev/null +++ b/lib/awesome_print/formatters/mongo_mapper.rb @@ -0,0 +1,21 @@ +module AwesomePrint + module Formatters + module MongoMapper + + def initialize(*args) + super(*args) + apply_default_mongo_mapper_options + end + + private + + def apply_default_mongo_mapper_options + @options[:color][:assoc] ||= :greenish + @options[:mongo_mapper] ||= { + :show_associations => false, # Display association data for MongoMapper documents and classes. + :inline_embedded => false # Display embedded associations inline with MongoMapper documents. + } + end + end + end +end diff --git a/lib/awesome_print/formatters/mongo_mapper_association.rb b/lib/awesome_print/formatters/mongo_mapper_association.rb new file mode 100644 index 00000000..2a2b5059 --- /dev/null +++ b/lib/awesome_print/formatters/mongo_mapper_association.rb @@ -0,0 +1,17 @@ +module AwesomePrint + module Formatters + class MongoMapperAssociation < Formatter + + def call + return object.inspect if !defined?(::ActiveSupport::OrderedHash) + return awesome_object(object) if @options[:raw] + + association = object.class.name.split('::').last.titleize.downcase.sub(/ association$/,'') + association = "embeds #{association}" if object.embeddable? + class_name = object.class_name + + "#{formatter.colorize(association, :assoc)} #{formatter.colorize(class_name, :class)}" + end + end + end +end diff --git a/lib/awesome_print/formatters/mongo_mapper_bson_id.rb b/lib/awesome_print/formatters/mongo_mapper_bson_id.rb new file mode 100644 index 00000000..f45788cc --- /dev/null +++ b/lib/awesome_print/formatters/mongo_mapper_bson_id.rb @@ -0,0 +1,10 @@ +module AwesomePrint + module Formatters + class MongoMapperBsonId < Formatter + + def call + object.inspect + end + end + end +end diff --git a/lib/awesome_print/formatters/mongo_mapper_class.rb b/lib/awesome_print/formatters/mongo_mapper_class.rb new file mode 100644 index 00000000..3530c4d9 --- /dev/null +++ b/lib/awesome_print/formatters/mongo_mapper_class.rb @@ -0,0 +1,32 @@ +require 'awesome_print/formatters/mongo_mapper' + +module AwesomePrint + module Formatters + class MongoMapperClass < Formatter + include MongoMapper + + def call + return object.inspect if !defined?(::ActiveSupport::OrderedHash) || !object.respond_to?(:keys) + + "class #{object} < #{object.superclass} " << AwesomePrint::Formatters::Hash.new(formatter, columns).call + end + + private + + def columns + data = object.keys.sort.inject(::ActiveSupport::OrderedHash.new) do |hash, c| + hash[c.first] = (c.last.type || "undefined").to_s.underscore.intern + hash + end + + # Add in associations + if options[:mongo_mapper][:show_associations] + object.associations.each do |name, assoc| + data[name.to_s] = assoc + end + end + data + end + end + end +end diff --git a/lib/awesome_print/formatters/mongo_mapper_instance.rb b/lib/awesome_print/formatters/mongo_mapper_instance.rb new file mode 100644 index 00000000..fbbb8418 --- /dev/null +++ b/lib/awesome_print/formatters/mongo_mapper_instance.rb @@ -0,0 +1,52 @@ +require 'awesome_print/formatters/mongo_mapper' + +module AwesomePrint + module Formatters + class MongoMapperInstance < Formatter + include MongoMapper + + # Format MongoMapper instance object. + # + # NOTE: by default only instance attributes (i.e. keys) are shown. To format + # MongoMapper instance as regular object showing its instance variables and + # accessors use :raw => true option: + # + # ap record, :raw => true + # + #------------------------------------------------------------------------------ + def call + return object.inspect if !defined?(::ActiveSupport::OrderedHash) + return AwesomePrint::Formatters::Object.new(formatter, object).call if options[:raw] + + "#{label} " << AwesomePrint::Formatters::Hash.new(formatter, columns).call + end + + private + + def label + label = object.to_s + label = "#{formatter.colorize('embedded', :assoc)} #{label}" if object.is_a?(::MongoMapper::EmbeddedDocument) + label + end + + def columns + data = object.keys.keys.sort_by{|k| k}.inject(::ActiveSupport::OrderedHash.new) do |hash, name| + hash[name] = object[name] + hash + end + + # Add in associations + if options[:mongo_mapper][:show_associations] + object.associations.each do |name, assoc| + if options[:mongo_mapper][:inline_embedded] and assoc.embeddable? + data[name.to_s] = object.send(name) + else + data[name.to_s] = assoc + end + end + end + data + end + end + end +end diff --git a/lib/awesome_print/formatters/mongoid_bson_id.rb b/lib/awesome_print/formatters/mongoid_bson_id.rb new file mode 100644 index 00000000..3d0be01e --- /dev/null +++ b/lib/awesome_print/formatters/mongoid_bson_id.rb @@ -0,0 +1,10 @@ +module AwesomePrint + module Formatters + class MongoidBsonId < Formatter + + def call + object.inspect + end + end + end +end diff --git a/lib/awesome_print/formatters/mongoid_class.rb b/lib/awesome_print/formatters/mongoid_class.rb new file mode 100644 index 00000000..bd69f6f9 --- /dev/null +++ b/lib/awesome_print/formatters/mongoid_class.rb @@ -0,0 +1,21 @@ +module AwesomePrint + module Formatters + class MongoidClass < Formatter + + def call + return object.inspect if !defined?(::ActiveSupport::OrderedHash) || !object.respond_to?(:fields) + + "class #{object} < #{object.superclass} " << AwesomePrint::Formatters::Hash.new(formatter, columns).call + end + + private + + def columns + object.fields.sort_by { |key| key }.inject(::ActiveSupport::OrderedHash.new) do |hash, c| + hash[c[1].name.to_sym] = (c[1].type || "undefined").to_s.underscore.intern + hash + end + end + end + end +end diff --git a/lib/awesome_print/formatters/mongoid_document.rb b/lib/awesome_print/formatters/mongoid_document.rb new file mode 100644 index 00000000..5b9b9b33 --- /dev/null +++ b/lib/awesome_print/formatters/mongoid_document.rb @@ -0,0 +1,24 @@ +module AwesomePrint + module Formatters + class MongoidDocument < Formatter + + def call + return object.inspect if !defined?(::ActiveSupport::OrderedHash) + "#{object} #{AwesomePrint::Formatters::Hash.new(formatter, columns).call}" + end + + private + + def columns + data = (object.attributes || {}).sort_by { |key| key }.inject(::ActiveSupport::OrderedHash.new) do |hash, c| + hash[c[0].to_sym] = c[1] + hash + end + if !object.errors.empty? + data = {:errors => object.errors, :attributes => data} + end + data + end + end + end +end diff --git a/lib/awesome_print/formatters/nobrainer_class.rb b/lib/awesome_print/formatters/nobrainer_class.rb new file mode 100644 index 00000000..a5ae9691 --- /dev/null +++ b/lib/awesome_print/formatters/nobrainer_class.rb @@ -0,0 +1,18 @@ +module AwesomePrint + module Formatters + class NobrainerClass < Formatter + + def call + "class #{object} < #{object.superclass} " << AwesomePrint::Formatters::Hash.new(formatter, columns).call + end + + private + + def columns + ::Hash[object.fields.map do |field, opt| + [field, (opt[:type] || ::Object).to_s.underscore.to_sym] + end] + end + end + end +end diff --git a/lib/awesome_print/formatters/nobrainer_document.rb b/lib/awesome_print/formatters/nobrainer_document.rb new file mode 100644 index 00000000..879336d0 --- /dev/null +++ b/lib/awesome_print/formatters/nobrainer_document.rb @@ -0,0 +1,20 @@ +module AwesomePrint + module Formatters + class NobrainerDocument < Formatter + + def call + "#{object} #{AwesomePrint::Formatters::Hash.new(formatter, columns).call}" + end + + private + + def columns + data = object.inspectable_attributes.symbolize_keys + if object.errors.present? + data = {:errors => object.errors, :attributes => data} + end + data + end + end + end +end diff --git a/lib/awesome_print/formatters/nokogiri_xml_node.rb b/lib/awesome_print/formatters/nokogiri_xml_node.rb new file mode 100644 index 00000000..4300d664 --- /dev/null +++ b/lib/awesome_print/formatters/nokogiri_xml_node.rb @@ -0,0 +1,29 @@ +module AwesomePrint + module Formatters + class NokogiriXmlNode < Formatter + + def call + if empty? + return "[]" + end + xml = object.to_xml(:indent => 2) + # + # Colorize tag, id/class name, and contents. + # + xml.gsub!(/(<)(\/?[A-Za-z1-9]+)/) { |tag| "#{$1}#{formatter.colorize($2, :keyword)}" } + xml.gsub!(/(id|class)="[^"]+"/i) { |id| formatter.colorize(id, :class) } + xml.gsub!(/>([^<]+)#{contents}<" + end + xml + end + + private + + def empty? + object.is_a?(::Nokogiri::XML::NodeSet) && object.empty? + end + end + end +end diff --git a/lib/awesome_print/formatters/object.rb b/lib/awesome_print/formatters/object.rb new file mode 100644 index 00000000..b0b2917d --- /dev/null +++ b/lib/awesome_print/formatters/object.rb @@ -0,0 +1,65 @@ +module AwesomePrint + module Formatters + class Object < Formatter + + def call + build_vars + build_data + if options[:multiline] + inline_format + else + multiline_format + end + end + + private + + def build_vars + @vars = object.instance_variables.map do |var| + property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet. + accessor = if object.respond_to?(:"#{property}=") + object.respond_to?(property) ? :accessor : :writer + else + object.respond_to?(property) ? :reader : nil + end + if accessor + [ "attr_#{accessor} :#{property}", var ] + else + [ var.to_s, var ] + end + end + end + + def build_data + @data = @vars.sort.map do |declaration, var| + key = formatter.left_aligned do + formatter.align(declaration, declaration.size) + end + + unless options[:plain] + if key =~ /(@\w+)/ + key.sub!($1, formatter.colorize($1, :variable)) + else + key.sub!(/(attr_\w+)\s(\:\w+)/, "#{formatter.colorize('\\1', :keyword)} #{formatter.colorize('\\2', :method)}") + end + end + formatter.indented do + key << formatter.colorize(" = ", :hash) + inspector.awesome(object.instance_variable_get(var)) + end + end + end + + def inline_format + "#<#{awesome_instance(object)}\n#{@data.join(%Q/,\n/)}\n#{formatter.outdent}>" + end + + def multiline_format + "#<#{awesome_instance(object)} #{@data.join(', ')}>" + end + + def awesome_instance(o) + "#{o.class}:0x%08x" % (o.__id__ * 2) + end + end + end +end diff --git a/lib/awesome_print/formatters/open_struct_instance.rb b/lib/awesome_print/formatters/open_struct_instance.rb new file mode 100644 index 00000000..cca03450 --- /dev/null +++ b/lib/awesome_print/formatters/open_struct_instance.rb @@ -0,0 +1,10 @@ +module AwesomePrint + module Formatters + class OpenStructInstance < Formatter + + def call + "#{object.class} #{AwesomePrint::Formatters::Hash.new(formatter, object.marshal_dump).call}" + end + end + end +end diff --git a/lib/awesome_print/formatters/rational.rb b/lib/awesome_print/formatters/rational.rb new file mode 100644 index 00000000..1a9da120 --- /dev/null +++ b/lib/awesome_print/formatters/rational.rb @@ -0,0 +1,10 @@ +module AwesomePrint + module Formatters + class Rational < Formatter + + def call + formatter.colorize(object.to_s, :rational) + end + end + end +end diff --git a/lib/awesome_print/formatters/ripple_document_class.rb b/lib/awesome_print/formatters/ripple_document_class.rb new file mode 100644 index 00000000..fd55c305 --- /dev/null +++ b/lib/awesome_print/formatters/ripple_document_class.rb @@ -0,0 +1,22 @@ +module AwesomePrint + module Formatters + class RippleDocumentClass < Formatter + + def call + return object.inspect if !defined?(::ActiveSupport::OrderedHash) || !object.respond_to?(:properties) + + "class #{object} < #{object.superclass} " << AwesomePrint::Formatters::Hash.new(formatter, columns).call + end + + private + + def columns + data = object.properties.inject(::ActiveSupport::OrderedHash.new) do |hash, (name, defn)| + hash[name.to_sym] = defn.type.to_s.downcase.to_sym + hash + end + data + end + end + end +end diff --git a/lib/awesome_print/formatters/ripple_document_instance.rb b/lib/awesome_print/formatters/ripple_document_instance.rb new file mode 100644 index 00000000..8fe0d838 --- /dev/null +++ b/lib/awesome_print/formatters/ripple_document_instance.rb @@ -0,0 +1,40 @@ +module AwesomePrint + module Formatters + class RippleDocumentInstance < Formatter + + # Format Ripple instance object. + # + # NOTE: by default only instance attributes are shown. To format a Ripple document instance + # as a regular object showing its instance variables and accessors use :raw => true option: + # + # ap document, :raw => true + # + #------------------------------------------------------------------------------ + def call + return object.inspect if !defined?(::ActiveSupport::OrderedHash) + return AwesomePrint::Formatters::Object.new(formatter, object).call if options[:raw] + + "#{object} " << AwesomePrint::Formatters::Hash.new(formatter, columns).call + end + + private + + def columns + exclude_assoc = options[:exclude_assoc] or options[:exclude_associations] + + data = object.attributes.inject(::ActiveSupport::OrderedHash.new) do |hash, (name, value)| + hash[name.to_sym] = object.send(name) + hash + end + + unless exclude_assoc + data = object.class.embedded_associations.inject(data) do |hash, assoc| + hash[assoc.name] = object.get_proxy(assoc) # Should always be array or Ripple::EmbeddedDocument for embedded associations + hash + end + end + data + end + end + end +end diff --git a/lib/awesome_print/formatters/self.rb b/lib/awesome_print/formatters/self.rb new file mode 100644 index 00000000..d5b497f2 --- /dev/null +++ b/lib/awesome_print/formatters/self.rb @@ -0,0 +1,34 @@ +module AwesomePrint + module Formatters + class Self < Formatter + + def call + if options[:raw] && object.instance_variables.any? + return AwesomePrint::Formatters::Object.new(formatter, object).call + elsif hash = convert_to_hash(object) + AwesomePrint::Formatters::Hash.new(formatter, hash).call + else + formatter.colorize(object.inspect.to_s, formatter.type) + end + end + + private + + def convert_to_hash(object) + if ! object.respond_to?(:to_hash) + return nil + end + if object.method(:to_hash).arity != 0 + return nil + end + + hash = object.to_hash + if ! hash.respond_to?(:keys) || ! hash.respond_to?('[]') + return nil + end + + return hash + end + end + end +end diff --git a/lib/awesome_print/formatters/sequel_dataset.rb b/lib/awesome_print/formatters/sequel_dataset.rb new file mode 100644 index 00000000..5bfae74a --- /dev/null +++ b/lib/awesome_print/formatters/sequel_dataset.rb @@ -0,0 +1,11 @@ +module AwesomePrint + module Formatters + class SequelDataset < Formatter + + def call + [AwesomePrint::Formatters::Array.new(formatter, object.to_a).call, + awesome_print(dataset.sql)].join("\n") + end + end + end +end diff --git a/lib/awesome_print/formatters/sequel_document.rb b/lib/awesome_print/formatters/sequel_document.rb new file mode 100644 index 00000000..186187ff --- /dev/null +++ b/lib/awesome_print/formatters/sequel_document.rb @@ -0,0 +1,17 @@ +module AwesomePrint + module Formatters + class SequelDocument < Formatter + + def call + data = object.values.sort_by { |key| key.to_s }.inject({}) do |hash, c| + hash[c[0].to_sym] = c[1] + hash + end + if !object.errors.empty? + data = {:errors => object.errors, :values => data} + end + "#{object} #{AwesomePrint::Formatters::Hash.new(formatter, data).call}" + end + end + end +end diff --git a/lib/awesome_print/formatters/sequel_model_class.rb b/lib/awesome_print/formatters/sequel_model_class.rb new file mode 100644 index 00000000..9510880d --- /dev/null +++ b/lib/awesome_print/formatters/sequel_model_class.rb @@ -0,0 +1,11 @@ +module AwesomePrint + module Formatters + class SequelModelClass < Formatter + + def call + data = object.db_schema.inject({}) {|h, (name,data)| h.merge(name => data[:db_type])} + "class #{object} < #{object.superclass} " << AwesomePrint::Formatters::Hash.new(formatter, data).call + end + end + end +end diff --git a/lib/awesome_print/formatters/set.rb b/lib/awesome_print/formatters/set.rb new file mode 100644 index 00000000..01d3bf2b --- /dev/null +++ b/lib/awesome_print/formatters/set.rb @@ -0,0 +1,10 @@ +module AwesomePrint + module Formatters + class Set < Formatter + + def call + AwesomePrint::Formatters::Array.new(formatter, object.to_a).call + end + end + end +end diff --git a/lib/awesome_print/formatters/struct.rb b/lib/awesome_print/formatters/struct.rb new file mode 100644 index 00000000..d4512e16 --- /dev/null +++ b/lib/awesome_print/formatters/struct.rb @@ -0,0 +1,16 @@ +module AwesomePrint + module Formatters + class Struct < Formatter + # + # The code is slightly uglier because of Ruby 1.8.6 quirks: + # awesome_hash(Hash[s.members.zip(s.values)]) <-- ArgumentError: odd number of arguments for Hash) + # awesome_hash(Hash[*s.members.zip(s.values).flatten]) <-- s.members returns strings, not symbols. + # + def call + hash = {} + object.each_pair { |key, value| hash[key] = value } + AwesomePrint::Formatters::Hash.new(formatter, hash).call + end + end + end +end diff --git a/lib/awesome_print/formatters/unboundmethod.rb b/lib/awesome_print/formatters/unboundmethod.rb new file mode 100644 index 00000000..5fa5cdfd --- /dev/null +++ b/lib/awesome_print/formatters/unboundmethod.rb @@ -0,0 +1,10 @@ +module AwesomePrint + module Formatters + class Unboundmethod < Formatter + + def call + AwesomePrint::Formatters::Method.new(formatter, object).call + end + end + end +end diff --git a/lib/awesome_print/inspector.rb b/lib/awesome_print/inspector.rb index 0893a90a..f9009775 100644 --- a/lib/awesome_print/inspector.rb +++ b/lib/awesome_print/inspector.rb @@ -1,68 +1,21 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ module AwesomePrint - - class << self # Class accessors for custom defaults. - attr_accessor :defaults, :force_colors - - # Class accessor to force colorized output (ex. forked subprocess where TERM - # might be dumb). - #------------------------------------------------------------------------------ - def force_colors!(value = true) - @force_colors = value - end - - def console? - !!(defined?(IRB) || defined?(Pry)) - end - - def rails_console? - console? && !!(defined?(Rails::Console) || ENV["RAILS_ENV"]) - end - - def irb! - return unless defined?(IRB) - unless IRB.version.include?("DietRB") - IRB::Irb.class_eval do - def output_value - ap @context.last_value - end - end - else # MacRuby - IRB.formatter = Class.new(IRB::Formatter) do - def inspect_object(object) - object.ai - end - end.new - end - end - - def pry! - if defined?(Pry) - Pry.print = proc { |output, value| output.puts value.ai } - end - end - end - class Inspector attr_accessor :options AP = :__awesome_print__ def initialize(options = {}) - @options = { - :indent => 4, # Indent using 4 spaces. - :index => true, # Display array indices. - :html => false, # Use ANSI color codes rather than HTML. - :multiline => true, # Display in multiple lines. - :plain => false, # Use colors. - :raw => false, # Do not recursively format object instance variables. - :sort_keys => false, # Do not sort hash keys. - :limit => false, # Limit large output for arrays and hashes. Set to a boolean or integer. - :color => { + @options = { + :indent => 4, # Indent using 4 spaces. + :index => true, # Display array indices. + :html => false, # Use ANSI color codes rather than HTML. + :multiline => true, # Display in multiple lines. + :plain => false, # Use colors. + :raw => false, # Do not recursively format object instance variables. + :sort_keys => false, # Do not sort hash keys. + :limit => false, # Limit large output for arrays and hashes. Set to a boolean or integer. + :colonize_symbol_keys => false, # Use the foo: 'bar' syntax, when the key is a symbol + :color => { :args => :pale, :array => :white, :bigdecimal => :blue, @@ -92,16 +45,16 @@ def initialize(options = {}) @formatter = AwesomePrint::Formatter.new(self) Thread.current[AP] ||= [] end - + # Dispatcher that detects data nesting and invokes object-aware formatter. #------------------------------------------------------------------------------ def awesome(object) if Thread.current[AP].include?(object.object_id) - nested(object) + @formatter.nested(object) else begin Thread.current[AP] << object.object_id - unnested(object) + @formatter.unnested(object) ensure Thread.current[AP].pop end @@ -117,40 +70,6 @@ def colorize? private - # Format nested data, for example: - # arr = [1, 2]; arr << arr - # => [1,2, [...]] - # hash = { :a => 1 }; hash[:b] = hash - # => { :a => 1, :b => {...} } - #------------------------------------------------------------------------------ - def nested(object) - case printable(object) - when :array then @formatter.colorize("[...]", :array) - when :hash then @formatter.colorize("{...}", :hash) - when :struct then @formatter.colorize("{...}", :struct) - else @formatter.colorize("...#{object.class}...", :class) - end - end - - #------------------------------------------------------------------------------ - def unnested(object) - @formatter.format(object, printable(object)) - end - - # Turn class name into symbol, ex: Hello::World => :hello_world. Classes that - # inherit from Array, Hash, File, Dir, and Struct are treated as the base class. - #------------------------------------------------------------------------------ - def printable(object) - case object - when Array then :array - when Hash then :hash - when File then :file - when Dir then :dir - when Struct then :struct - else object.class.to_s.gsub(/:+/, "_").downcase.to_sym - end - end - # Update @options by first merging the :color hash and then the remaining keys. #------------------------------------------------------------------------------ def merge_options!(options = {}) diff --git a/lib/awesome_print/support.rb b/lib/awesome_print/support.rb new file mode 100644 index 00000000..496855ec --- /dev/null +++ b/lib/awesome_print/support.rb @@ -0,0 +1,35 @@ +module AwesomePrint + class Support + + def self.constantize(camel_cased_word) + names = camel_cased_word.split('::') + # Trigger a built-in NameError exception including the ill-formed constant in the message. + Object.const_get(camel_cased_word) if names.empty? + # Remove the first blank element in case of '::ClassName' notation. + names.shift if names.size > 1 && names.first.empty? + names.inject(Object) do |constant, name| + if constant == Object + constant.const_get(name) + else + candidate = constant.const_get(name) + next candidate if constant.const_defined?(name, false) + next candidate unless Object.const_defined?(name) + # Go down the ancestors to check if it is owned directly. The check + # stops when we reach Object or the end of ancestors tree. + constant = constant.ancestors.inject do |const, ancestor| + break const if ancestor == Object + break ancestor if ancestor.const_defined?(name, false) + const + end + # owner is in Object, so raise + constant.const_get(name, false) + end + end + end + + def self.camelize(term) + term = term.capitalize + term.gsub(/(?:_|(\/))([a-z\d]*)/i) { $2.capitalize } + end + end +end diff --git a/lib/awesome_print/type_discover.rb b/lib/awesome_print/type_discover.rb new file mode 100644 index 00000000..d543a751 --- /dev/null +++ b/lib/awesome_print/type_discover.rb @@ -0,0 +1,50 @@ +require 'awesome_print/types/type' + +module AwesomePrint + class TypeDiscover + + BUILT_IN_TYPES = [ :array, :bigdecimal, :class, :dir, :file, :hash, :method, :rational, :set, :struct, :unboundmethod ] + + def initialize(formatter) + @type = formatter.type + @object = formatter.object + @custom_types = [] + require_custom_types + end + + def call + custom_type || built_in_type || :self + end + + private + + attr_reader :object, :type, :custom_types + + def custom_type + custom_types.map do |type| + begin + klass = AwesomePrint::Support.constantize("AwesomePrint::Types::#{type}") + klass.new(object).call + rescue NameError + nil + end + end.detect { |type| !type.nil? } + end + + def built_in_type + BUILT_IN_TYPES.grep(type)[0] + end + + def require_custom_types + Dir[File.dirname(__FILE__) + '/types/*.rb'].each do |file| + add_custom_type(file) + require file + end + end + + def add_custom_type(file) + file_name = File.basename(file, '.rb') + @custom_types << AwesomePrint::Support.camelize(file_name) + end + end +end diff --git a/lib/awesome_print/types/active_record.rb b/lib/awesome_print/types/active_record.rb new file mode 100644 index 00000000..edac9ac6 --- /dev/null +++ b/lib/awesome_print/types/active_record.rb @@ -0,0 +1,16 @@ +module AwesomePrint + module Types + class ActiveRecord < Type + + def call + if object.is_a?(::ActiveRecord::Base) + :active_record_instance + elsif object.is_a?(Class) && object.ancestors.include?(::ActiveRecord::Base) + :active_record_class + elsif object.class.ancestors.include?(::ActiveRecord::Relation) + :array + end + end + end + end +end diff --git a/lib/awesome_print/types/active_support.rb b/lib/awesome_print/types/active_support.rb new file mode 100644 index 00000000..e0b4a00b --- /dev/null +++ b/lib/awesome_print/types/active_support.rb @@ -0,0 +1,18 @@ +if defined?(ActiveSupport::LogSubscriber) + AwesomePrint.force_colors! ActiveSupport::LogSubscriber.colorize_logging +end + +module AwesomePrint + module Types + class ActiveSupport < Type + + def call + if (defined?(::ActiveSupport::TimeWithZone) && object.is_a?(::ActiveSupport::TimeWithZone)) || object.is_a?(::Date) + :active_support_time + elsif object.is_a?(::HashWithIndifferentAccess) + :hash_with_indifferent_access + end + end + end + end +end diff --git a/lib/awesome_print/types/mongo_mapper.rb b/lib/awesome_print/types/mongo_mapper.rb new file mode 100644 index 00000000..f51899db --- /dev/null +++ b/lib/awesome_print/types/mongo_mapper.rb @@ -0,0 +1,18 @@ +module AwesomePrint + module Types + class MongoMapper < Type + + def call + if object.is_a?(Class) && (object.ancestors & [ ::MongoMapper::Document, ::MongoMapper::EmbeddedDocument ]).size > 0 + :mongo_mapper_class + elsif object.is_a?(::MongoMapper::Document) || object.is_a?(::MongoMapper::EmbeddedDocument) + :mongo_mapper_instance + elsif object.is_a?(::MongoMapper::Plugins::Associations::Base) + :mongo_mapper_association + elsif object.is_a?(::BSON::ObjectId) + :mongo_mapper_bson_id + end + end + end + end +end diff --git a/lib/awesome_print/types/mongoid.rb b/lib/awesome_print/types/mongoid.rb new file mode 100644 index 00000000..235d3177 --- /dev/null +++ b/lib/awesome_print/types/mongoid.rb @@ -0,0 +1,16 @@ +module AwesomePrint + module Types + class Mongoid < Type + + def call + if object.is_a?(Class) && object.ancestors.include?(::Mongoid::Document) + :mongoid_class + elsif object.class.ancestors.include?(::Mongoid::Document) + :mongoid_document + elsif (defined?(::BSON) && object.is_a?(::BSON::ObjectId)) || (defined?(::Moped::BSON) && object.is_a?(::Moped::BSON::ObjectId)) + :mongoid_bson_id + end + end + end + end +end diff --git a/lib/awesome_print/types/no_brainer.rb b/lib/awesome_print/types/no_brainer.rb new file mode 100644 index 00000000..d22362fd --- /dev/null +++ b/lib/awesome_print/types/no_brainer.rb @@ -0,0 +1,14 @@ +module AwesomePrint + module Types + class NoBrainer < Type + + def call + if object.is_a?(Class) && object < ::NoBrainer::Document + :nobrainer_class + elsif object.is_a?(::NoBrainer::Document) + :nobrainer_document + end + end + end + end +end diff --git a/lib/awesome_print/types/nokogiri.rb b/lib/awesome_print/types/nokogiri.rb new file mode 100644 index 00000000..2f7b2e0b --- /dev/null +++ b/lib/awesome_print/types/nokogiri.rb @@ -0,0 +1,13 @@ +module AwesomePrint + module Types + class Nokogiri < Type + + def call + if (defined?(::Nokogiri::XML::Node) && object.is_a?(::Nokogiri::XML::Node)) || + (defined?(::Nokogiri::XML::NodeSet) && object.is_a?(::Nokogiri::XML::NodeSet)) + :nokogiri_xml_node + end + end + end + end +end diff --git a/lib/awesome_print/types/open_struct.rb b/lib/awesome_print/types/open_struct.rb new file mode 100644 index 00000000..cc55d5a5 --- /dev/null +++ b/lib/awesome_print/types/open_struct.rb @@ -0,0 +1,12 @@ +module AwesomePrint + module Types + class OpenStruct < Type + + def call + if (defined?(::OpenStruct)) && (object.is_a?(::OpenStruct)) + :open_struct_instance + end + end + end + end +end diff --git a/lib/awesome_print/types/ripple.rb b/lib/awesome_print/types/ripple.rb new file mode 100644 index 00000000..33874a26 --- /dev/null +++ b/lib/awesome_print/types/ripple.rb @@ -0,0 +1,14 @@ +module AwesomePrint + module Types + class Ripple < Type + + def call + if object.is_a?(::Ripple::AttributeMethods) # Module used to access attributes across documents and embedded documents + :ripple_document_instance + elsif object.is_a?(::Ripple::Properties) # Used to access property metadata on Ripple classes + :ripple_document_class + end + end + end + end +end diff --git a/lib/awesome_print/types/sequel.rb b/lib/awesome_print/types/sequel.rb new file mode 100644 index 00000000..9e52f5f2 --- /dev/null +++ b/lib/awesome_print/types/sequel.rb @@ -0,0 +1,16 @@ +module AwesomePrint + module Types + class Sequel < Type + + def call + if defined?(::Sequel::Model) && object.is_a?(::Sequel::Model) + :sequel_document + elsif defined?(::Sequel::Model) && object.is_a?(Class) && object.ancestors.include?(::Sequel::Model) + :sequel_model_class + elsif defined?(::Sequel::Mysql2::Dataset) && object.class.ancestors.include?(::Sequel::Mysql2::Dataset) + :sequel_dataset + end + end + end + end +end diff --git a/lib/awesome_print/types/type.rb b/lib/awesome_print/types/type.rb new file mode 100644 index 00000000..6c0efc20 --- /dev/null +++ b/lib/awesome_print/types/type.rb @@ -0,0 +1,14 @@ +module AwesomePrint + module Types + class Type + + def initialize(object) + @object = object + end + + private + + attr_reader :object + end + end +end diff --git a/lib/awesome_print/version.rb b/lib/awesome_print/version.rb index 0e1edabc..9c7a37dd 100644 --- a/lib/awesome_print/version.rb +++ b/lib/awesome_print/version.rb @@ -1,10 +1,5 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ module AwesomePrint def self.version - '1.6.2' + '2.0.0.beta' end end diff --git a/rails/init.rb b/rails/init.rb deleted file mode 100644 index ef0b9190..00000000 --- a/rails/init.rb +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ -# -# Load awesome_print when installed as Rails 2.3.x plugin. -# -require File.join(File.dirname(__FILE__), "..", "init") unless defined?(AwesomePrint) diff --git a/spec/ext/active_record_spec.rb b/spec/ext/active_record_spec.rb index 6b67ac38..ed2b611b 100644 --- a/spec/ext/active_record_spec.rb +++ b/spec/ext/active_record_spec.rb @@ -27,11 +27,7 @@ :rank => 1 } EOS - if RUBY_VERSION < '1.9' - str.sub!('?', 'Sat Oct 10 12:30:00 UTC 1992') - else - str.sub!('?', '1992-10-10 12:30:00 UTC') - end + str.sub!('?', '1992-10-10 12:30:00 UTC') expect(out.gsub(/0x([a-f\d]+)/, "0x01234567")).to eq(str) end @@ -55,13 +51,8 @@ } ] EOS - if RUBY_VERSION < '1.9' - str.sub!('??', 'Sat Oct 10 12:30:00 UTC 1992') - str.sub!('?!', 'Mon May 26 14:15:00 UTC 2003') - else - str.sub!('??', '1992-10-10 12:30:00 UTC') - str.sub!('?!', '2003-05-26 14:15:00 UTC') - end + str.sub!('??', '1992-10-10 12:30:00 UTC') + str.sub!('?!', '2003-05-26 14:15:00 UTC') expect(out.gsub(/0x([a-f\d]+)/, "0x01234567")).to eq(str) end @@ -87,13 +78,8 @@ } ] EOS - if RUBY_VERSION < '1.9' - str.sub!('??', 'Sat Oct 10 12:30:00 UTC 1992') - str.sub!('?!', 'Mon May 26 14:15:00 UTC 2003') - else - str.sub!('??', '1992-10-10 12:30:00 UTC') - str.sub!('?!', '2003-05-26 14:15:00 UTC') - end + str.sub!('??', '1992-10-10 12:30:00 UTC') + str.sub!('?!', '2003-05-26 14:15:00 UTC') expect(out.gsub(/0x([a-f\d]+)/, "0x01234567")).to eq(str) end end @@ -154,21 +140,10 @@ >, attr_reader :value = 1992-10-10 12:30:00 UTC, attr_reader :value_before_type_cast = "1992-10-10 12:30:00" - >, - "id" => #, - attr_reader :value = nil, - attr_reader :value_before_type_cast = nil >, "name" => #, - "name" => # #, attr_reader :value = 1992-10-10 12:30:00 UTC, attr_reader :value_before_type_cast = "1992-10-10 12:30:00" - >, - "id" => #, - attr_reader :value = nil, - attr_reader :value_before_type_cast = nil >, "name" => #, - "name" => # #, attr_reader :value = 1992-10-10 12:30:00 UTC, attr_reader :value_before_type_cast = "1992-10-10 12:30:00" - >, - "id" => #, - attr_reader :value = nil, - attr_reader :value_before_type_cast = nil >, "name" => #, - "name" => # #, attr_reader :value = 2003-05-26 14:15:00 UTC, attr_reader :value_before_type_cast = "2003-05-26 14:15:00" - >, - "id" => #, - attr_reader :value = nil, - attr_reader :value_before_type_cast = nil >, "name" => #, - "name" => # #, attr_reader :value = 1992-10-10 12:30:00 UTC, attr_reader :value_before_type_cast = "1992-10-10 12:30:00" - >, - "id" => #, - attr_reader :value = nil, - attr_reader :value_before_type_cast = nil >, "name" => #, - "name" => # #, attr_reader :value = 2003-05-26 14:15:00 UTC, attr_reader :value_before_type_cast = "2003-05-26 14:15:00" - >, - "id" => #, - attr_reader :value = nil, - attr_reader :value_before_type_cast = nil >, "name" => #, - "name" => # #= "3.2" - if RUBY_VERSION >= "1.9" - expect(out).to match(/\sfirst\(\*args,\s&block\)\s+Class \(ActiveRecord::Querying\)/) - else - expect(out).to match(/\sfirst\(\*arg1\)\s+Class \(ActiveRecord::Querying\)/) - end + expect(out).to match(/\sfirst\(\*args,\s&block\)\s+Class \(ActiveRecord::Querying\)/) else expect(out).to match(/\sfirst\(\*arg.*?\)\s+User \(ActiveRecord::Base\)/) end diff --git a/spec/formats_spec.rb b/spec/formats_spec.rb index 4c1c8ace..83a5124e 100644 --- a/spec/formats_spec.rb +++ b/spec/formats_spec.rb @@ -275,6 +275,24 @@ EOS end + it "new hash syntax" do + expect(@hash.ai(:plain => true, :colonize_symbol_keys => true)).to eq <<-EOS.strip +{ + 1 => { + sym: { + "str" => { + [ 1, 2, 3 ] => { + { k: :v } => Hash < Object + } + } + } + } +} +EOS + end + + + it "plain multiline indented" do expect(@hash.ai(:plain => true, :indent => 1)).to eq <<-EOS.strip { @@ -311,6 +329,22 @@ EOS end + it "colored with new hash syntax" do + expect(@hash.ai(:colonize_symbol_keys => true)).to eq <<-EOS.strip +{ + 1\e[0;37m => \e[0m{ + sym\e[0;37m: \e[0m{ + \"str\"\e[0;37m => \e[0m{ + [ 1, 2, 3 ]\e[0;37m => \e[0m{ + { k: :v }\e[0;37m => \e[0m\e[1;33mHash < Object\e[0m + } + } + } + } +} +EOS + end + it "colored multiline indented" do expect(@hash.ai(:indent => 2)).to eq <<-EOS.strip { @@ -361,14 +395,7 @@ it "plain multiline" do out = @hash.ai(:plain => true) - if RUBY_VERSION.to_f < 1.9 # Order of @hash keys is not guaranteed. - expect(out).to match(/^\{[^\}]+\}/m) - expect(out).to match(/ "b" => "b",?/) - expect(out).to match(/ :a => "a",?/) - expect(out).to match(/ :z => "z",?/) - expect(out).to match(/ "alpha" => "alpha",?$/) - else - expect(out).to eq <<-EOS.strip + expect(out).to eq <<-EOS.strip { "b" => "b", :a => "a", @@ -376,7 +403,6 @@ "alpha" => "alpha" } EOS - end end it "plain multiline with sorted keys" do @@ -488,16 +514,7 @@ it "should present Rational object with arbitrary precision" do rat = Rational(201020102010201020102010201020102010, 2) out = rat.ai(:plain => true) - # - # Ruby 1.9 slightly changed the format of Rational#to_s, see - # http://techtime.getharvest.com/blog/harvest-is-now-on-ruby-1-dot-9-3 and - # http://www.ruby-forum.com/topic/189397 - # - if RUBY_VERSION < "1.9" - expect(out).to eq("100510051005100510051005100510051005") - else - expect(out).to eq("100510051005100510051005100510051005/1") - end + expect(out).to eq("100510051005100510051005100510051005/1") end end @@ -523,38 +540,20 @@ expect(Set.new.ai).to eq([].ai) end - if RUBY_VERSION > "1.9" - it "plain multiline" do - expect(@set.ai(:plain => true)).to eq(@arr.ai(:plain => true)) - end - - it "plain multiline indented" do - expect(@set.ai(:plain => true, :indent => 1)).to eq(@arr.ai(:plain => true, :indent => 1)) - end - - it "plain single line" do - expect(@set.ai(:plain => true, :multiline => false)).to eq(@arr.ai(:plain => true, :multiline => false)) - end - - it "colored multiline (default)" do - expect(@set.ai).to eq(@arr.ai) - end - else # Prior to Ruby 1.9 the order of set values is unpredicatble. - it "plain multiline" do - expect(@set.sort_by{ |x| x.to_s }.ai(:plain => true)).to eq(@arr.sort_by{ |x| x.to_s }.ai(:plain => true)) - end + it "plain multiline" do + expect(@set.ai(:plain => true)).to eq(@arr.ai(:plain => true)) + end - it "plain multiline indented" do - expect(@set.sort_by{ |x| x.to_s }.ai(:plain => true, :indent => 1)).to eq(@arr.sort_by{ |x| x.to_s }.ai(:plain => true, :indent => 1)) - end + it "plain multiline indented" do + expect(@set.ai(:plain => true, :indent => 1)).to eq(@arr.ai(:plain => true, :indent => 1)) + end - it "plain single line" do - expect(@set.sort_by{ |x| x.to_s }.ai(:plain => true, :multiline => false)).to eq(@arr.sort_by{ |x| x.to_s }.ai(:plain => true, :multiline => false)) - end + it "plain single line" do + expect(@set.ai(:plain => true, :multiline => false)).to eq(@arr.ai(:plain => true, :multiline => false)) + end - it "colored multiline (default)" do - expect(@set.sort_by{ |x| x.to_s }.ai).to eq(@arr.sort_by{ |x| x.to_s }.ai) - end + it "colored multiline (default)" do + expect(@set.ai).to eq(@arr.ai) end end diff --git a/spec/methods_spec.rb b/spec/methods_spec.rb index 0ad25ab5..8aa55243 100644 --- a/spec/methods_spec.rb +++ b/spec/methods_spec.rb @@ -72,11 +72,7 @@ class Hello def world(a,b); end end method = Hello.instance_method(:world) - if RUBY_VERSION < '1.9.2' - expect(method.ai).to eq("\e[1;33mHello (unbound)\e[0m#\e[0;35mworld\e[0m\e[0;37m(arg1, arg2)\e[0m") - else - expect(method.ai).to eq("\e[1;33mHello (unbound)\e[0m#\e[0;35mworld\e[0m\e[0;37m(a, b)\e[0m") - end + expect(method.ai).to eq("\e[1;33mHello (unbound)\e[0m#\e[0;35mworld\e[0m\e[0;37m(a, b)\e[0m") end end @@ -140,11 +136,7 @@ class Hello protected def m3(a,b); end end - if RUBY_VERSION < '1.9.2' - expect(Hello.new.protected_methods.ai(:plain => true, :index => false)).to eq("[\n m3(arg1, arg2) Hello\n]") - else - expect(Hello.new.protected_methods.ai(:plain => true, :index => false)).to eq("[\n m3(a, b) Hello\n]") - end + expect(Hello.new.protected_methods.ai(:plain => true, :index => false)).to eq("[\n m3(a, b) Hello\n]") end end @@ -167,11 +159,7 @@ class Hello def m3(a,b); end end out = Hello.new.private_methods.ai(:plain => true).split("\n").grep(/m\d/) - if RUBY_VERSION < '1.9.2' - expect(out.first).to match(/^\s+\[\s*\d+\]\s+m3\(arg1, arg2\)\s+Hello$/) - else - expect(out.first).to match(/^\s+\[\s*\d+\]\s+m3\(a, b\)\s+Hello$/) - end + expect(out.first).to match(/^\s+\[\s*\d+\]\s+m3\(a, b\)\s+Hello$/) end end @@ -193,11 +181,7 @@ class Hello def self.m3(a,b); end end out = Hello.singleton_methods.ai(:plain => true, :index => false).split("\n").grep(/m\d/) - if RUBY_VERSION < '1.9.2' - expect(out.first).to match(/^\s+m3\(arg1, arg2\)\s+Hello$/) - else - expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello$/) - end + expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello$/) end end end @@ -227,11 +211,7 @@ class Hello def m3(a,b); end end out = Hello.instance_methods.ai(:plain => true, :index => false).split("\n").grep(/m\d/) - if RUBY_VERSION < '1.9.2' - expect(out.first).to match(/^\s+m3\(arg1, arg2\)\s+Hello\s\(unbound\)$/) - else - expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello\s\(unbound\)$/) - end + expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello\s\(unbound\)$/) end end @@ -251,11 +231,7 @@ class Hello def m3(a,b); end end out = Hello.public_instance_methods.ai(:plain => true, :index => false).split("\n").grep(/m\d/) - if RUBY_VERSION < '1.9.2' - expect(out.first).to match(/^\s+m3\(arg1, arg2\)\s+Hello\s\(unbound\)$/) - else - expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello\s\(unbound\)$/) - end + expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello\s\(unbound\)$/) end end @@ -277,11 +253,7 @@ class Hello def m3(a,b); end end out = Hello.protected_instance_methods.ai(:plain => true, :index => false).split("\n").grep(/m\d/) - if RUBY_VERSION < '1.9.2' - expect(out.first).to match(/^\s+m3\(arg1, arg2\)\s+Hello\s\(unbound\)$/) - else - expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello\s\(unbound\)$/) - end + expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello\s\(unbound\)$/) end end @@ -303,64 +275,58 @@ class Hello def m3(a,b); end end out = Hello.private_instance_methods.ai(:plain => true, :index => false).split("\n").grep(/m\d/) - if RUBY_VERSION < '1.9.2' - expect(out.first).to match(/^\s+m3\(arg1, arg2\)\s+Hello\s\(unbound\)$/) - else - expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello\s\(unbound\)$/) - end + expect(out.first).to match(/^\s+m3\(a, b\)\s+Hello\s\(unbound\)$/) end end end -if RUBY_VERSION >= '1.9.2' - RSpec.describe "Ruby 1.9.2+ Method#parameters" do - before do - stub_dotfile! - end +RSpec.describe "Ruby 1.9.2+ Method#parameters" do + before do + stub_dotfile! + end - after do - Object.instance_eval{ remove_const :Hello } if defined?(Hello) - end + after do + Object.instance_eval{ remove_const :Hello } if defined?(Hello) + end - it "()" do - class Hello - def m1; end - end - out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) - expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(\)\s+Hello$/) + it "()" do + class Hello + def m1; end end + out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) + expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(\)\s+Hello$/) + end - it ":req" do - class Hello - def m1(a, b, c); end - end - out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) - expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(a, b, c\)\s+Hello$/) + it ":req" do + class Hello + def m1(a, b, c); end end + out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) + expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(a, b, c\)\s+Hello$/) + end - it ":opt" do - class Hello - def m1(a, b = 1, c = 2); end # m1(a, *b, *c) - end - out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) - expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(a, \*b, \*c\)\s+Hello$/) + it ":opt" do + class Hello + def m1(a, b = 1, c = 2); end # m1(a, *b, *c) end + out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) + expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(a, \*b, \*c\)\s+Hello$/) + end - it ":rest" do - class Hello - def m1(*a); end # m1(*a) - end - out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) - expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(\*a\)\s+Hello$/) + it ":rest" do + class Hello + def m1(*a); end # m1(*a) end + out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) + expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(\*a\)\s+Hello$/) + end - it ":block" do - class Hello - def m1(a, b = nil, &blk); end # m1(a, *b, &blk) - end - out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) - expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(a, \*b, &blk\)\s+Hello$/) + it ":block" do + class Hello + def m1(a, b = nil, &blk); end # m1(a, *b, &blk) end + out = Hello.new.methods.ai(:plain => true).split("\n").grep(/m1/) + expect(out.first).to match(/^\s+\[\s*\d+\]\s+m1\(a, \*b, &blk\)\s+Hello$/) end end @@ -450,10 +416,6 @@ def her it "appending garbage to methods array should not raise error" do arr = 42.methods << [ :wtf ] expect { arr.ai(:plain => true) }.not_to raise_error - if RUBY_VERSION < '1.9.2' - expect(arr.ai(:plain => true)).to match(/\s+wtf\(\?\)\s+\?/) # [ :wtf ].to_s => "wtf" - else - expect(arr.ai(:plain => true)).to match(/\s+\[:wtf\]\(\?\)\s+\?/) # [ :wtf ].to_s => [:wtf] - end + expect(arr.ai(:plain => true)).to match(/\s+\[:wtf\]\(\?\)\s+\?/) # [ :wtf ].to_s => [:wtf] end end diff --git a/spec/misc_spec.rb b/spec/misc_spec.rb index 21b50ce6..f6be128a 100644 --- a/spec/misc_spec.rb +++ b/spec/misc_spec.rb @@ -32,13 +32,10 @@ def inspect expect(grepped.ai(:plain => true, :multiline => false)).to eq('[ "1", "2" ]') end - # See https://github.com/michaeldv/awesome_print/issues/85 - if RUBY_VERSION >= "1.8.7" - it "handle array grep when a method is defined in C and thus doesn't have a binding" do - arr = (0..6).to_a - grepped = arr.grep(1..4, &:succ) - expect(grepped.ai(:plain => true, :multiline => false)).to eq('[ 2, 3, 4, 5 ]') - end + it "handle array grep when a method is defined in C and thus doesn't have a binding" do + arr = (0..6).to_a + grepped = arr.grep(1..4, &:succ) + expect(grepped.ai(:plain => true, :multiline => false)).to eq('[ 2, 3, 4, 5 ]') end it "returns value passed as a parameter" do @@ -47,9 +44,8 @@ def inspect expect(ap object).to eq(object) end - # Require different file name this time (lib/ap.rb vs. lib/awesome_print). it "several require 'awesome_print' should do no harm" do - require File.expand_path(File.dirname(__FILE__) + '/../lib/ap') + require File.expand_path(File.dirname(__FILE__) + '/../lib/awesome_print') expect { rand.ai }.not_to raise_error end @@ -177,11 +173,7 @@ def ==(other) it "shoud not raise ArgumentError when formatting HTML" do out = "hello".ai(:color => { :string => :red }, :html => true) - if RUBY_VERSION >= "1.9" - expect(out).to eq(%Q|
[red]"hello"[/red]
|) - else - expect(out).to eq(%Q|
[red]"hello"[/red]
|) - end + expect(out).to eq(%Q|
[red]"hello"[/red]
|) end it "shoud not raise ArgumentError when formatting HTML (shade color)" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4d43a29f..1d983c5b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,19 +1,7 @@ -# Copyright (c) 2010-2013 Michael Dvorkin -# -# Awesome Print is freely distributable under the terms of MIT license. -# See LICENSE file or http://www.opensource.org/licenses/mit-license.php -#------------------------------------------------------------------------------ # # Running specs from the command line: # $ rake spec # Entire spec suite. # $ rspec spec/objects_spec.rb # Individual spec file. -# -# NOTE: To successfully run specs with Ruby 1.8.6 the older versions of -# Bundler and RSpec gems are required: -# -# $ gem install bundler -v=1.0.2 -# $ gem install rspec -v=2.6.0 -# require 'codeclimate-test-reporter' CodeClimate::TestReporter.start $LOAD_PATH.unshift(File.dirname(__FILE__))