gorillib 0.4.1pre → 0.4.2pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. data/.gitignore +13 -10
  2. data/.rspec +1 -1
  3. data/.yardopts +1 -0
  4. data/CHANGELOG.md +47 -0
  5. data/Gemfile +22 -19
  6. data/Guardfile +23 -9
  7. data/README.md +12 -12
  8. data/Rakefile +29 -40
  9. data/VERSION +1 -1
  10. data/examples/benchmark/factories_benchmark.rb +87 -0
  11. data/examples/builder/ironfan.rb +1 -19
  12. data/examples/hash/slicing_methods.rb +101 -0
  13. data/gorillib.gemspec +36 -35
  14. data/lib/gorillib/array/deep_compact.rb +4 -3
  15. data/lib/gorillib/array/simple_statistics.rb +76 -0
  16. data/lib/gorillib/base.rb +0 -1
  17. data/lib/gorillib/builder.rb +15 -30
  18. data/lib/gorillib/collection.rb +159 -57
  19. data/lib/gorillib/collection/model_collection.rb +136 -43
  20. data/lib/gorillib/datetime/parse.rb +4 -2
  21. data/lib/gorillib/{array → deprecated/array}/average.rb +0 -0
  22. data/lib/gorillib/{array → deprecated/array}/random.rb +2 -1
  23. data/lib/gorillib/{array → deprecated/array}/sorted_median.rb +0 -0
  24. data/lib/gorillib/{array → deprecated/array}/sorted_percentile.rb +0 -0
  25. data/lib/gorillib/deprecated/array/sorted_sample.rb +13 -0
  26. data/lib/gorillib/{metaprogramming → deprecated/metaprogramming}/aliasing.rb +0 -0
  27. data/lib/gorillib/enumerable/sum.rb +3 -3
  28. data/lib/gorillib/exception/raisers.rb +92 -22
  29. data/lib/gorillib/factories.rb +550 -0
  30. data/lib/gorillib/hash/mash.rb +15 -58
  31. data/lib/gorillib/hashlike/deep_compact.rb +2 -2
  32. data/lib/gorillib/hashlike/slice.rb +55 -40
  33. data/lib/gorillib/model.rb +5 -3
  34. data/lib/gorillib/model/base.rb +33 -119
  35. data/lib/gorillib/model/defaults.rb +58 -14
  36. data/lib/gorillib/model/errors.rb +10 -0
  37. data/lib/gorillib/model/factories.rb +1 -367
  38. data/lib/gorillib/model/field.rb +40 -18
  39. data/lib/gorillib/model/fixup.rb +16 -0
  40. data/lib/gorillib/model/positional_fields.rb +35 -0
  41. data/lib/gorillib/model/schema_magic.rb +162 -0
  42. data/lib/gorillib/model/serialization.rb +1 -2
  43. data/lib/gorillib/model/serialization/csv.rb +59 -0
  44. data/lib/gorillib/pathname.rb +19 -8
  45. data/lib/gorillib/some.rb +2 -0
  46. data/lib/gorillib/string/constantize.rb +17 -10
  47. data/lib/gorillib/string/inflector.rb +11 -7
  48. data/lib/gorillib/type/boolean.rb +40 -0
  49. data/lib/gorillib/type/extended.rb +76 -40
  50. data/lib/gorillib/type/url.rb +6 -4
  51. data/lib/gorillib/utils/console.rb +1 -18
  52. data/lib/gorillib/utils/edge_cases.rb +18 -0
  53. data/spec/examples/builder/ironfan_spec.rb +5 -10
  54. data/spec/gorillib/array/compact_blank_spec.rb +36 -21
  55. data/spec/gorillib/array/simple_statistics_spec.rb +143 -0
  56. data/spec/gorillib/builder_spec.rb +16 -20
  57. data/spec/gorillib/collection_spec.rb +131 -35
  58. data/spec/gorillib/exception/raisers_spec.rb +39 -0
  59. data/spec/gorillib/hash/deep_compact_spec.rb +3 -3
  60. data/spec/gorillib/model/{record/defaults_spec.rb → defaults_spec.rb} +5 -1
  61. data/spec/gorillib/model/factories_spec.rb +335 -0
  62. data/spec/gorillib/model/{record/overlay_spec.rb → overlay_spec.rb} +0 -0
  63. data/spec/gorillib/model/serialization_spec.rb +2 -2
  64. data/spec/gorillib/model_spec.rb +19 -18
  65. data/spec/gorillib/pathname_spec.rb +7 -7
  66. data/spec/gorillib/string/truncate_spec.rb +3 -13
  67. data/spec/gorillib/type/extended_spec.rb +50 -2
  68. data/spec/gorillib/utils/capture_output_spec.rb +1 -1
  69. data/spec/spec_helper.rb +10 -7
  70. data/spec/support/factory_test_helpers.rb +76 -0
  71. data/spec/support/gorillib_test_helpers.rb +36 -24
  72. data/spec/support/model_test_helpers.rb +39 -2
  73. metadata +86 -51
  74. data/lib/alt/kernel/call_stack.rb +0 -56
  75. data/lib/gorillib/array/sorted_sample.rb +0 -12
  76. data/lib/gorillib/builder/field.rb +0 -5
  77. data/lib/gorillib/collection/has_collection.rb +0 -31
  78. data/lib/gorillib/collection/list_collection.rb +0 -58
  79. data/lib/gorillib/exception/confidence.rb +0 -17
  80. data/lib/gorillib/io/system_helpers.rb +0 -30
  81. data/lib/gorillib/model/record_schema.rb +0 -9
  82. data/lib/gorillib/utils/stub_module.rb +0 -33
  83. data/spec/array/average_spec.rb +0 -24
  84. data/spec/array/sorted_median_spec.rb +0 -18
  85. data/spec/array/sorted_percentile_spec.rb +0 -24
  86. data/spec/array/sorted_sample_spec.rb +0 -28
  87. data/spec/gorillib/metaprogramming/aliasing_spec.rb +0 -180
  88. data/spec/gorillib/model/record/factories_spec.rb +0 -335
  89. data/spec/support/kcode_test_helper.rb +0 -16
@@ -15,7 +15,7 @@ module Gorillib
15
15
  attr_reader :model
16
16
 
17
17
  # [Hash] all options passed to the field not recognized by one of its own current fields
18
- attr_reader :extra_attributes
18
+ attr_reader :_extra_attributes
19
19
 
20
20
  # Note: `Gorillib::Model::Field` is assembled in two pieces, so that it
21
21
  # can behave as a model itself. Defining `name` here, along with some
@@ -28,7 +28,6 @@ module Gorillib
28
28
  class_attribute :visibilities, :instance_writer => false
29
29
  self.visibilities = { :reader => :public, :writer => :public, :receiver => :public, :tester => false }
30
30
 
31
-
32
31
  # @param [#to_sym] name Field name
33
32
  # @param [#receive] type Factory for field values. To accept any object as-is, specify `Object` as the type.
34
33
  # @param [Gorillib::Model] model Field's owner
@@ -38,11 +37,14 @@ module Gorillib
38
37
  # @option options [true, false, :public, :protected, :private] :writer Visibility for the writer (`#foo=`) method; `false` means don't create one.
39
38
  # @option options [true, false, :public, :protected, :private] :receiver Visibility for the receiver (`#receive_foo`) method; `false` means don't create one.
40
39
  #
41
- def initialize(name, type, model, options={})
40
+ def initialize(model, name, type, options={})
42
41
  Validate.identifier!(name)
42
+ type_opts = options.extract!(:blankish, :empty_product, :items, :keys, :of)
43
+ type_opts[:items] = type_opts.delete(:of) if type_opts.has_key?(:of)
44
+ #
43
45
  @model = model
44
46
  @name = name.to_sym
45
- @type = self.factory_for(type)
47
+ @type = Gorillib::Factory.factory_for(type, type_opts)
46
48
  default_visabilities = visibilities
47
49
  @visibilities = default_visabilities.merge( options.extract!(*default_visabilities.keys) )
48
50
  @doc = options.delete(:name){ "#{name} field" }
@@ -56,29 +58,28 @@ module Gorillib
56
58
  name.to_s
57
59
  end
58
60
 
59
- def factory_for(type)
60
- Gorillib::Factory(type)
61
- end
62
-
63
61
  # @return [String] Human-readable presentation of the field definition
64
62
  def inspect
65
- args = [name.inspect, type.to_s]
66
- "field(#{args.join(", ")})"
63
+ args = [name.inspect, type.to_s, attributes.reject{|k,v| k =~ /^(name|type)$/}.inspect]
64
+ "field(#{args.join(",")})"
65
+ end
66
+ def inspect_compact
67
+ "field(#{name})"
67
68
  end
68
69
 
69
70
  def to_hash
70
- attributes.merge!(@visibility).merge!(@extra_attributes)
71
+ attributes.merge!(@visibility).merge!(@_extra_attributes)
71
72
  end
72
73
 
73
74
  def ==(val)
74
- super && (val.extra_attributes == self.extra_attributes) && (val.model == self.model)
75
+ super && (val._extra_attributes == self._extra_attributes) && (val.model == self.model)
75
76
  end
76
77
 
77
78
  def self.receive(hsh)
78
79
  name = hsh.fetch(:name)
79
80
  type = hsh.fetch(:type)
80
81
  model = hsh.fetch(:model)
81
- new(name, type, model, hsh)
82
+ new(model, name, type, hsh)
82
83
  end
83
84
 
84
85
  #
@@ -110,22 +111,43 @@ module Gorillib
110
111
  # Now we can construct the actual fields.
111
112
  #
112
113
 
114
+ field :position, Integer, :tester => true, :doc => "Indicates this is a positional initialization arg -- you can pass it as a plain value in the given slot to #initialize"
115
+
113
116
  # Name of this field. Must start with `[A-Za-z_]` and subsequently contain only `[A-Za-z0-9_]` (required)
114
117
  # @macro [attach] field
115
118
  # @attribute $1
116
119
  # @return [$2] the $1 field $*
117
- field :name, String, :writer => false, :doc => "The field name. Must start with `[A-Za-z_]` and subsequently contain only `[A-Za-z0-9_]` (required)"
120
+ field :name, String, position: 0, writer: false, doc: "The field name. Must start with `[A-Za-z_]` and subsequently contain only `[A-Za-z0-9_]` (required)"
118
121
 
119
- # Factory for the field's values
120
- field :type, Class
122
+ field :type, Class, position: 1, doc: "Factory to generate field's values"
121
123
 
122
- # Field's description
123
- field :doc, String
124
+ field :doc, String, doc: "Field's description"
124
125
 
125
126
  # remove the attr_reader method (needed for scaffolding), leaving the meta_module method to remain
126
127
  remove_possible_method(:name)
127
128
 
128
129
  end
130
+
131
+
132
+ class SimpleCollectionField < Gorillib::Model::Field
133
+ field :item_type, Class, default: Whatever, doc: "Factory for collection items"
134
+ # field :collection_attrs, Hash, default: Hash.new, doc: "Extra attributes to pass to the collection on creation -- eg. key_method"
135
+
136
+ def initialize(model, name, type, options={})
137
+ super
138
+ collection_type = self.type
139
+ item_type = self.item_type
140
+ key_method = options[:key_method] if options[:key_method]
141
+ raise "Please supply an item type for #{self.inspect} -- eg 'collection #{name.inspect}, of: FooClass'" unless item_type
142
+ self.default ||= ->{ collection_type.new(item_type: item_type, belongs_to: self, key_method: key_method) }
143
+ end
144
+
145
+ def inscribe_methods(model)
146
+ super
147
+ model.__send__(:define_collection_receiver, self)
148
+ end
149
+ end
150
+
129
151
  end
130
152
  end
131
153
 
@@ -0,0 +1,16 @@
1
+ ::Gorillib::Model::Field.class_eval do
2
+ field :fixup, Symbol, doc: 'key to remap before receive', tester: true
3
+ end
4
+
5
+ module ::Gorillib::StringFixup
6
+ extend Gorillib::Concern
7
+
8
+ # intercept to replace fixup-able hash keys with the proper field name in the receive hash
9
+ def receive!(hsh={})
10
+ self.class.fields.each do |field_name, field|
11
+ next unless field.fixup?
12
+ hsh[field_name] = hsh.delete(field.fixup) if hsh.has_key?(field.fixup)
13
+ end
14
+ super(hsh)
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module Gorillib
2
+ module Model
3
+
4
+ #
5
+ # give each field the next position in order
6
+ #
7
+ # @example
8
+ # class Foo
9
+ # include Gorillib::Model
10
+ # field :bob, String # not positional
11
+ # field :zoe, String, position: 0 # positional 0 (explicit)
12
+ # end
13
+ # class Subby < Foo
14
+ # include Gorillib::Model::PositionalFields
15
+ # field :wun, String # positional 1
16
+ # end
17
+ # Foo.field :nope, String # not positional
18
+ # Subby.field :toofer, String # positional 2
19
+ #
20
+ # @note: make sure you're keeping positionals straight in super classes, or
21
+ # in anything added after this.
22
+ #
23
+ module PositionalFields
24
+ extend Gorillib::Concern
25
+
26
+ module ClassMethods
27
+ def field(*args)
28
+ options = args.extract_options!
29
+ super(*args, {position: positionals.count}.merge(options))
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,162 @@
1
+ module Gorillib
2
+ module Model
3
+
4
+ module ClassMethods
5
+
6
+ # Defines a new field
7
+ #
8
+ # For each field that is defined, a getter and setter will be added as
9
+ # an instance method to the model. An Field instance will be added to
10
+ # result of the fields class method.
11
+ #
12
+ # @example
13
+ # field :height, Integer
14
+ #
15
+ # @param [Symbol] field_name The field name. Must start with `[A-Za-z_]` and subsequently contain only `[A-Za-z0-9_]`
16
+ # @param [Class] type The field's type (required)
17
+ # @option options [String] doc Documentation string for the field (optional)
18
+ # @option options [Proc, Object] default Default value, or proc that instance can evaluate to find default value
19
+ #
20
+ # @return Gorillib::Model::Field
21
+ def field(field_name, type, options={})
22
+ options = options.symbolize_keys
23
+ field_type = options.delete(:field_type){ ::Gorillib::Model::Field }
24
+ fld = field_type.new(self, field_name, type, options)
25
+ @_own_fields[fld.name] = fld
26
+ _reset_descendant_fields
27
+ fld.send(:inscribe_methods, self)
28
+ fld
29
+ end
30
+
31
+ def collection(field_name, collection_type, options={})
32
+ options[:item_type] = options[:of] if options.has_key?(:of)
33
+ field(field_name, collection_type, {
34
+ field_type: ::Gorillib::Model::SimpleCollectionField}.merge(options))
35
+ end
36
+
37
+ # @return [{Symbol => Gorillib::Model::Field}]
38
+ def fields
39
+ return @_fields if defined?(@_fields)
40
+ @_fields = ancestors.reverse.inject({}){|acc, ancestor| acc.merge!(ancestor.try(:_own_fields) || {}) }
41
+ end
42
+
43
+ # @return [true, false] true if the field is defined on this class
44
+ def has_field?(field_name)
45
+ fields.has_key?(field_name)
46
+ end
47
+
48
+ # @return [Array<Symbol>] The attribute names
49
+ def field_names
50
+ @_field_names ||= fields.keys
51
+ end
52
+
53
+ def positionals
54
+ @_positionals ||= assemble_positionals
55
+ end
56
+
57
+ def assemble_positionals
58
+ positionals = fields.values.keep_if{|fld| fld.position? }.sort_by!{|fld| fld.position }
59
+ return [] if positionals.empty?
60
+ if (positionals.map(&:position) != (0..positionals.length-1).to_a) then raise ConflictingPositionError, "field positions #{positionals.map(&:position).join(",")} for #{positionals.map(&:name).join(",")} aren't in strict minimal order" ; end
61
+ positionals.map!(&:name)
62
+ end
63
+
64
+ # turn model constructor args (`*positional_args, {attrs}`) into a combined
65
+ # attrs hash. positional_args are mapped to the set of attribute names in
66
+ # order -- by default, the class' field names.
67
+ #
68
+ # Notes:
69
+ #
70
+ # * Positional args always clobber elements of the attribute hash.
71
+ # * Nil positional args are treated as present-and-nil (this might change).
72
+ # * Raises an error if positional args
73
+ #
74
+ # @param [Array[Symbol]] args list of attributes, in order, to map.
75
+ #
76
+ # @return [Hash] a combined, reconciled hash of attributes to set
77
+ def attrs_hash_from_args(args)
78
+ attrs = args.extract_options!
79
+ if args.present?
80
+ ArgumentError.check_arity!(args, 0..positionals.length){ "extracting args #{args} for #{self}" }
81
+ positionals_to_map = positionals[0..(args.length-1)]
82
+ attrs = attrs.merge(Hash[positionals_to_map.zip(args)])
83
+ end
84
+ attrs
85
+ end
86
+
87
+ protected
88
+
89
+ attr_reader :_own_fields
90
+
91
+ # Ensure that classes inherit all their parents' fields, even if fields
92
+ # are added after the child class is defined.
93
+ def _reset_descendant_fields
94
+ ObjectSpace.each_object(::Class) do |klass|
95
+ klass.__send__(:remove_instance_variable, '@_fields') if (klass <= self) && klass.instance_variable_defined?('@_fields')
96
+ klass.__send__(:remove_instance_variable, '@_field_names') if (klass <= self) && klass.instance_variable_defined?('@_field_names')
97
+ klass.__send__(:remove_instance_variable, '@_positionals') if (klass <= self) && klass.instance_variable_defined?('@_positionals')
98
+ end
99
+ end
100
+
101
+ # define the reader method `#foo` for a field named `:foo`
102
+ def define_attribute_reader(field_name, field_type, visibility)
103
+ define_meta_module_method(field_name, visibility) do
104
+ begin
105
+ read_attribute(field_name)
106
+ rescue StandardError => err ; err.polish("#{self.class}.#{field_name}") rescue nil ; raise ; end
107
+ end
108
+ end
109
+
110
+ # define the writer method `#foo=` for a field named `:foo`
111
+ def define_attribute_writer(field_name, field_type, visibility)
112
+ define_meta_module_method("#{field_name}=", visibility) do |val|
113
+ write_attribute(field_name, val)
114
+ end
115
+ end
116
+
117
+ # define the present method `#foo?` for a field named `:foo`
118
+ def define_attribute_tester(field_name, field_type, visibility)
119
+ field = fields[field_name]
120
+ define_meta_module_method("#{field_name}?", visibility) do
121
+ attribute_set?(field_name) || field.has_default?
122
+ end
123
+ end
124
+
125
+ def define_attribute_receiver(field_name, field_type, visibility)
126
+ # @param [Object] val the raw value to type-convert and adopt
127
+ # @return [Object] the attribute's new value
128
+ define_meta_module_method("receive_#{field_name}", visibility) do |val|
129
+ begin
130
+ val = field_type.receive(val)
131
+ write_attribute(field_name, val)
132
+ rescue StandardError => err ; err.polish("#{self.class}.#{field_name} type #{type} on #{val}") rescue nil ; raise ; end
133
+ end
134
+ end
135
+
136
+ #
137
+ # Collection receiver --
138
+ #
139
+ def define_collection_receiver(field)
140
+ collection_field_name = field.name; collection_type = field.type
141
+ # @param [Array[Object],Hash[Object]] the collection to merge
142
+ # @return [Gorillib::Collection] the updated collection
143
+ define_meta_module_method("receive_#{collection_field_name}", true) do |coll, &block|
144
+ begin
145
+ if collection_type.native?(coll)
146
+ write_attribute(collection_field_name, coll)
147
+ else
148
+ read_attribute(collection_field_name).receive!(coll, &block)
149
+ end
150
+ rescue StandardError => err ; err.polish("#{self.class} #{collection_field_name} collection on #{args}'") rescue nil ; raise ; end
151
+ end
152
+ end
153
+
154
+ def inherited(base)
155
+ base.instance_eval do
156
+ @_own_fields ||= {}
157
+ end
158
+ super
159
+ end
160
+ end
161
+ end
162
+ end
@@ -1,4 +1,3 @@
1
-
2
1
  class Array
3
2
  def to_tsv
4
3
  join("\t")
@@ -25,7 +24,7 @@ module Gorillib
25
24
 
26
25
  module ClassMethods
27
26
  def from_tuple(*vals)
28
- receive Hash[field_names[0..vals.length].zip(vals)]
27
+ receive Hash[field_names[0..vals.length-1].zip(vals)]
29
28
  end
30
29
  end
31
30
 
@@ -0,0 +1,59 @@
1
+ require 'csv'
2
+ require 'gorillib/pathname'
3
+
4
+ module Gorillib
5
+ module Model
6
+
7
+ module LoadFromCsv
8
+ extend Gorillib::Concern
9
+ included do |base|
10
+ # Options that will be passed to CSV. Be careful to modify with assignment (`+=`) and not in-place (`<<`)
11
+ base.class_attribute :csv_options
12
+ base.csv_options = Hash.new
13
+ end
14
+
15
+ module ClassMethods
16
+
17
+ # Iterate a block over each line of a CSV file
18
+ #
19
+ # @raise [Gorillib::Model::RawDataMismatchError] if a line has too many or too few fields
20
+ # @yield an object instantiated from each line in the file.
21
+ def each_in_csv(filename, options={})
22
+ filename = Pathname.path_to(filename)
23
+ options = csv_options.merge(options)
24
+ pop_headers = options.delete(:pop_headers)
25
+ num_fields = options.delete(:num_fields){ (fields.length .. fields.length) }
26
+ raise ArgumentError, "The :headers option to CSV changes its internal behavior; use 'pop_headers: true' to ignore the first line" if options[:headers]
27
+ CSV.open(filename, options) do |csv_file|
28
+ csv_file.shift if pop_headers
29
+ csv_file.each do |tuple|
30
+ next if tuple.empty?
31
+ unless num_fields.include?(tuple.length) then raise Gorillib::Model::RawDataMismatchError, "yark, spurious fields: #{tuple.inspect}" ; end
32
+ yield from_tuple(*tuple)
33
+ end
34
+ nil
35
+ end
36
+ end
37
+
38
+ # With a block, calls block on each object in turn (and returns nil)
39
+ #
40
+ # With no block, accumulates all the instances into the array it
41
+ # returns. As opposed to the with-a-block case, the memory footprint of
42
+ # this increases as the filesize does, so use caution with large files.
43
+ #
44
+ # @return with a block, returns nil; with no block, an array of this class' instances
45
+ def load_csv(*args)
46
+ if block_given?
47
+ each_in_csv(*args, &Proc.new)
48
+ else
49
+ objs = []
50
+ each_in_csv(*args){|obj| objs << obj }
51
+ objs
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -52,9 +52,11 @@ module Gorillib
52
52
  # any mixture of strings (literal sub-paths) and symbols (interpreted as references)
53
53
  # @return [Pathname] A single expanded Pathname
54
54
  #
55
- def path_to(*pathsegs)
56
- relative_path_to(*pathsegs).expand_path
55
+ def of(*pathsegs)
56
+ relpath_to(*pathsegs).expand_path
57
57
  end
58
+ alias_method :path_to, :of
59
+
58
60
 
59
61
  # Expand a path with late-evaluated segments
60
62
  # @see `.path_to`
@@ -62,16 +64,12 @@ module Gorillib
62
64
  # Calls cleanpath (removing `//` double slashes and useless `..`s), but does
63
65
  # not reference the filesystem or make paths absolute
64
66
  #
65
- def relative_path_to(*pathsegs)
67
+ def relpath_to(*pathsegs)
66
68
  ArgumentError.arity_at_least!(pathsegs, 1)
67
69
  pathsegs = pathsegs.map{|ps| expand_pathseg(ps) }.flatten
68
70
  self.new(File.join(*pathsegs)).cleanpath(true)
69
71
  end
70
- def relpath_to(*args) relative_path_to(*args) ; end
71
-
72
- # def make_pathname(*args)
73
- # Pathname.new(*args)
74
- # end
72
+ alias_method :relative_path_to, :relpath_to
75
73
 
76
74
  protected
77
75
  # Recursively expand a path handle
@@ -88,6 +86,19 @@ class Pathname
88
86
  extend Gorillib::Pathref
89
87
  class << self ; alias_method :new_pathname, :new ; end
90
88
 
89
+ def self.receive(obj)
90
+ return obj if obj.nil?
91
+ obj.is_a?(self) ? obj : new(obj)
92
+ end
93
+
94
+ # @return the basename without extension (using self.extname as the extension)
95
+ def corename
96
+ basename(self.extname)
97
+ end
98
+
99
+ # @return [String] compact string rendering
100
+ def inspect_compact() to_path.dump ; end
101
+
91
102
  # FIXME: find out if this is dangerous
92
103
  alias_method :to_str, :to_path
93
104
  end