README.md in object_inspector-0.2.0 vs README.md in object_inspector-0.3.0
- old
+ new
@@ -1,9 +1,9 @@
# ObjectInspector
[![Gem Version](https://badge.fury.io/rb/object_inspector.svg)](https://badge.fury.io/rb/object_inspector)
-[![Build Status](https://travis-ci.org/objects-on-rails/display-case.svg?branch=master)](https://travis-ci.org/objects-on-rails/display-case)
+[![Build Status](https://travis-ci.org/pdobb/object_inspector.svg?branch=master)](https://travis-ci.org/pdobb/object_inspector)
[![Test Coverage](https://api.codeclimate.com/v1/badges/34e821263d9e0c33d536/test_coverage)](https://codeclimate.com/github/pdobb/object_inspector/test_coverage)
[![Maintainability](https://api.codeclimate.com/v1/badges/34e821263d9e0c33d536/maintainability)](https://codeclimate.com/github/pdobb/object_inspector/maintainability)
ObjectInspector takes Object#inspect to the next level. Specify any combination of identification attributes, flags, info, and/or a name along with an optional self-definable scope option to represent an object in the console, in logging, etc.
@@ -30,12 +30,30 @@
Tested MRI Ruby Versions:
* 2.2.10
* 2.3.7
* 2.4.4
* 2.5.1
+* edge
+## Configuration
+
+Global/default values for ObjectInspector can be configured via the ObjectInspector::Configuration object.
+
+_Note: In a Rails app, the following would go in e.g. `config/initializers/object_inspector.rb`_
+
+```ruby
+# Default values are shown.
+ObjectInspector.configure do |config|
+ config.wild_card_scope = "all"
+ config.out_of_scope_placeholder = "*"
+ config.flags_separator = " / "
+ config.info_separator = " | "
+end
+```
+
+
## Usage
Given, an object of any type, call ObjectInspector::Inspector.inspect.
```ruby
@@ -58,17 +76,17 @@
```ruby
class MyObject
def inspect
ObjectInspector::Inspector.inspect(self,
identification: "My Object",
- flags: "FLAG1",
+ flags: "FLAG1 / FLAG2",
info: "INFO",
name: "NAME")
end
end
-MyObject.new.inspect # => "<My Object(FLAG1) INFO :: NAME>"
+MyObject.new.inspect # => "<My Object(FLAG1 / FLAG2) INFO :: NAME>"
```
Or, define `inspect_identification`, `inspect_flags`, `inspect_info`, and `inspect_name` as either public or private methods on Object.
```ruby
@@ -78,16 +96,16 @@
end
private
def inspect_identification; "My Object" end
- def inspect_flags; "FLAG1" end
+ def inspect_flags; "FLAG1 / FLAG2" end
def inspect_info; "INFO" end
def inspect_name; "NAME" end
end
-MyObject.new.inspect # => "<My Object(FLAG1) INFO :: NAME>"
+MyObject.new.inspect # => "<My Object(FLAG1 / FLAG2) INFO :: NAME>"
```
## Helper Usage
@@ -116,74 +134,194 @@
end
MyObject.new.inspect # => "<My Object(FLAG1) INFO :: NAME>"
```
-Or, define `inspect_identification`, `inspect_flags`, `inspect_info`, and `inspect_name` in Object.
+Or, define `inspect_identification`, `inspect_flags`, `inspect_info`, and `inspect_name` (or `display_name`) in Object.
```ruby
class MyObject
include ObjectInspector::InspectorsHelper
private
def inspect_identification; "My Object" end
- def inspect_flags; "FLAG1" end
+ def inspect_flags; "FLAG1 / FLAG2" end
def inspect_info; "INFO" end
- def inspect_name; "NAME" end
+ def inspect_name; "NAME" end # Or: def display_name; "NAME" end
end
-MyObject.new.inspect # => "<My Object(FLAG1) INFO :: NAME>"
+MyObject.new.inspect # => "<My Object(FLAG1 / FLAG2) INFO :: NAME>"
```
-## On-the-fly Inspect Methods
+## Scopes
-When passed as an option (as opposed to being called via an Object-defined method) symbols will be called/evaluated on Object on the fly.
+Use the `scope` option to define the scope of the `inspect_*` methods. The supplied value will be wrapped by the ObjectInspector::Scope helper object.
+The default value is `ObjectInspector::Scope.new(:self)`.
+
+### Scope Names
+
+ObjectInspector::Scope acts like [ActiveSupport::StringInquirer](http://api.rubyonrails.org/classes/ActiveSupport/StringInquirer.html). This is a prettier way to test for a given type of "scope" within objects.
+
+The ObjectInspector::Scope objects in these examples are the same as specifying `<scope_name>` like this:
+
```ruby
-class MyObject
- include ObjectInspector::InspectorsHelper
+my_object.inspect(scope: <scope_name>)
+```
- def my_method1; "Result1" end
- def my_method2; "Result2" end
- def inspect_info; :my_method2 end
-end
+Options:
+- `:self` (Default) -- Is meant to confine object interrogation to self (don't interrogate neighboring objects).
+- `:all` -- Is meant to match on all scopes, regardless of their name.
+- `<custom>` -- Anything else that makes sense for the object to key on.
-MyObject.new.inspect(info: "my_method1") # => "<MyObject my_method1>"
-MyObject.new.inspect(info: :my_method2) # => "<MyObject Result2>"
-MyObject.new.inspect # => "<MyObject my_method2>"
+```ruby
+scope = ObjectInspector::Scope.new
+scope.self? # => true
+scope.verbose? # => false
+scope.complex? # => false
```
-#### Scope
+#### Multiple Scope Names
-Use the `scope` option to define the scope of the `inspect_*` methods.
+It is also possible to pass in multiple scope names to match on.
-If ActiveSupport::StringInquirer is defined then the default `scope` is `"self".inquiry`.
-The default value is `:self` if ActiveSupport::StringInquirer is not defined.
+```ruby
+scope = ObjectInspector::Scope.new(%i[verbose complex])
+scope.self? # => false
+scope.verbose? # => true
+scope.complex? # => true
+```
+
+#### The "Wild Card" Scope
+
+Finally, `:all` is a "wild card" scope name, and will match on all scope names.
+
```ruby
+scope = ObjectInspector::Scope.new(:all)
+scope.self? # => true
+scope.verbose? # => true
+scope.complex? # => true
+```
+
+
+### Scope blocks
+
+Passing a block to a scope predicate falls back to the out-of-scope placeholder (`*` by default) if the scope does not match.
+
+```ruby
+scope = ObjectInspector::Scope.new(:verbose)
+scope.verbose? { "MATCH" } # => "MATCH"
+scope.complex? { "MATCH" } # => "*"
+```
+
+
+### Scope Joiners
+
+ObjectInspector::Scope also offers helper methods for uniformly joining inspect elements:
+- `join_flags` -- Joins flags with ` / ` by default
+- `join_info` -- Joins info items with ` | ` by default
+
+```ruby
+scope = ObjectInspector::Scope.new(:verbose)
+scope.join_flags([1, 2, 3]) # => "1 / 2 / 3"
+scope.join_info([1, 2, 3]) # => "1 | 2 | 3"
+```
+
+
+### Conversion to ObjectInspector::Scope
+
+ObjectInspector::Conversions.Scope() is available for proper conversion to ObjectInspector::Scope objects. Though this should rarely be necessary as conversion is performed automatically when calling `<my_object>.inspect(scope: <scope_name>)`.
+
+```ruby
+ObjectInspector::Conversions.Scope(:self)
+# => #<ObjectInspector::Scope:0x007ff78ab8e7f8 @name="self">
+
+scope = ObjectInspector::Scope.new(:verbose)
+result = ObjectInspector::Conversions.Scope(scope)
+# => #<ObjectInspector::Scope:0x007ff78ac9c140 @name="verbose">
+
+scope.object_id == result.object_id # => true
+```
+
+
+## Full Example
+
+```ruby
class MyObject
include ObjectInspector::InspectorsHelper
- def inspect_flags(scope:, separator: " / ".freeze)
- flags = ["FLAG1"]
+ attr_reader :name,
+ :a2
- # If ActiveSupport::StringInquirer is defined, use this:
- # flags << "FLAG2" if scope.all?
+ def initialize(name, a2 = 2)
+ @name = name
+ @a2 = a2
+ end
- # If ActiveSupport::StringInquirer is not defined, use this:
- flags << "FLAG2" if scope == :all
+ def associated_object1
+ OpenStruct.new(flags: "AO1_FLAG1")
+ end
- flags.join(separator)
+ def associated_object2
+ OpenStruct.new(flags: "AO2_FLAG1")
end
+
+private
+
+ def inspect_identification
+ identify(:a2)
+ end
+
+ def inspect_flags(scope:)
+ flags = ["DEFAULT_FLAG"]
+
+ flags <<
+ scope.verbose? {
+ [
+ associated_object1.flags,
+ associated_object2.flags,
+ ]
+ }
+
+ scope.join_flags(flags)
+ end
+
+ def inspect_info(scope:)
+ info = ["Default Info"]
+ info << "Complex Info" if scope.complex?
+ info << scope.verbose? { "Verbose Info" }
+
+ scope.join_info(info)
+ end
+
+ # Or `def inspect_name`
+ def display_name
+ name
+ end
end
-MyObject.new.inspect # => "<MyObject(FLAG1)>"
-MyObject.new.inspect(scope: :all) # => "<MyObject(FLAG1 / FLAG2)>"
+my_object = MyObject.new("Name")
+
+my_object.inspect
+# => "<MyObject[a2:2](DEFAULT_FLAG / *) Default Info | * :: Name>"
+
+my_object.inspect(scope: :complex)
+# => "<MyObject[a2:2](DEFAULT_FLAG / *) Default Info | Complex Info | * :: Name>"
+
+my_object.inspect(scope: :verbose)
+# => "<MyObject[a2:2](DEFAULT_FLAG / AO1_FLAG1 / AO2_FLAG1) Default Info | Verbose Info :: Name>"
+
+my_object.inspect(scope: %i[self complex verbose])
+# => "<MyObject[a2:2](DEFAULT_FLAG / AO1_FLAG1 / AO2_FLAG1) Default Info | Complex Info | Verbose Info :: Name>"
+
+my_object.inspect(scope: :all)
+# => "<MyObject[a2:2](DEFAULT_FLAG / AO1_FLAG1 / AO2_FLAG1) Default Info | Complex Info | Verbose Info :: Name>"
```
## Wrapped Objects
@@ -205,21 +343,41 @@
class MyWrappedObject
include ObjectInspector::InspectorsHelper
private
- def inspect_flags; "FLAG1" end
+ def inspect_flags; "FLAG1 / FLAG2" end
def inspect_info; "INFO" end
end
MyWrapperObject.new.inspect
-# => "<MyWrapperObject(WRAPPER_FLAG1)> ⇨ <MyWrappedObject(FLAG1) INFO>"
+# => "<MyWrapperObject(WRAPPER_FLAG1)> ⇨ <MyWrappedObject(FLAG1 / FLAG2) INFO>"
```
This feature is recursive.
+## On-the-fly Inspect Methods
+
+When passed as an option (as opposed to being called via an Object-defined method) symbols will be called/evaluated on Object on the fly.
+
+```ruby
+class MyObject
+ include ObjectInspector::InspectorsHelper
+
+ def my_method1; "Result1" end
+ def my_method2; "Result2" end
+
+ def inspect_info; :my_method2 end
+end
+
+MyObject.new.inspect(info: "my_method1") # => "<MyObject my_method1>"
+MyObject.new.inspect(info: :my_method2) # => "<MyObject Result2>"
+MyObject.new.inspect # => "<MyObject my_method2>"
+```
+
+
## Custom Formatters
A custom inspect formatter can be defined by implementing the interface defined by [ObjectInspector::BaseFormatter](https://github.com/pdobb/object_inspector/blob/master/lib/object_inspector/formatters/base_formatter.rb) and then passing that into ObjectInspector::Inspector.new.
```ruby
@@ -233,22 +391,23 @@
include ObjectInspector::InspectorsHelper
def inspect
super(formatter: MyCustomFormatter,
identification: "IDENTIFICATION",
- flags: "FLAG1 | FLAG2",
+ flags: "FLAG1 / FLAG2",
info: "INFO",
name: "NAME")
end
end
MyObject.new.inspect
-# => "[IDENTIFICATION Flags: FLAG1 | FLAG2 -- Info: INFO -- Name: NAME]"
+# => "[IDENTIFICATION Flags: FLAG1 / FLAG2 -- Info: INFO -- Name: NAME]"
```
-See also: [ObjectInspector::TemplatingFormatter].
-See also: [ObjectInspector::CombiningFormatter].
+See examples:
+- [ObjectInspector::TemplatingFormatter]
+- [ObjectInspector::CombiningFormatter]
## Performance
### Benchmarking ObjectInspector
@@ -281,10 +440,11 @@
# ObjectInspector::CombiningFormatter: 34973.9 i/s - 1.31x slower
#
# == Done
```
+
#### Benchmarking Custom Formatters
Custom Formatters may be similarly gauged for comparison by adding them to the `custom_formatter_klasses` array before playing the script.
```ruby
@@ -310,26 +470,29 @@
```ruby
class MyObject
include ObjectInspector::InspectorsHelper
def my_method1
- "Result1"
+ 1
end
def my_method2
- "Result2"
+ 2
end
private
- def inspect_identification; identify(:my_method1, :my_method2) end
- def inspect_flags; "FLAG1" end
+ def inspect_identification
+ identify(:my_method1, :my_method2)
+ end
+
+ def inspect_flags; "FLAG1 / FLAG2" end
def inspect_info; "INFO" end
def inspect_name; "NAME" end
end
MyObject.new.inspect
-# => "<MyObject[my_method1:Result1, my_method2:Result2](FLAG1) INFO :: NAME>"
+# => "<MyObject[my_method1:1, my_method2:2](FLAG1 / FLAG2) INFO :: NAME>"
```
## Development