jinx 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.yardopts +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +27 -0
- data/History.md +6 -0
- data/LEGAL +5 -0
- data/LICENSE +22 -0
- data/README.md +44 -0
- data/Rakefile +41 -0
- data/examples/family/README.md +10 -0
- data/examples/family/ext/build.xml +35 -0
- data/examples/family/ext/src/family/Address.java +68 -0
- data/examples/family/ext/src/family/Child.java +24 -0
- data/examples/family/ext/src/family/DomainObject.java +26 -0
- data/examples/family/ext/src/family/Household.java +36 -0
- data/examples/family/ext/src/family/Parent.java +48 -0
- data/examples/family/ext/src/family/Person.java +42 -0
- data/examples/family/lib/family.rb +15 -0
- data/examples/family/lib/family/address.rb +6 -0
- data/examples/family/lib/family/domain_object.rb +6 -0
- data/examples/family/lib/family/household.rb +6 -0
- data/examples/family/lib/family/parent.rb +16 -0
- data/examples/family/lib/family/person.rb +6 -0
- data/examples/model/README.md +25 -0
- data/examples/model/ext/build.xml +35 -0
- data/examples/model/ext/src/domain/Child.java +192 -0
- data/examples/model/ext/src/domain/Dependent.java +29 -0
- data/examples/model/ext/src/domain/DomainObject.java +26 -0
- data/examples/model/ext/src/domain/Independent.java +83 -0
- data/examples/model/ext/src/domain/Parent.java +129 -0
- data/examples/model/ext/src/domain/Person.java +14 -0
- data/examples/model/lib/model.rb +13 -0
- data/examples/model/lib/model/child.rb +13 -0
- data/examples/model/lib/model/domain_object.rb +6 -0
- data/examples/model/lib/model/independent.rb +11 -0
- data/examples/model/lib/model/parent.rb +17 -0
- data/jinx.gemspec +22 -0
- data/lib/jinx.rb +3 -0
- data/lib/jinx/active_support/README.txt +2 -0
- data/lib/jinx/active_support/core_ext/string.rb +7 -0
- data/lib/jinx/active_support/core_ext/string/inflections.rb +167 -0
- data/lib/jinx/active_support/inflections.rb +55 -0
- data/lib/jinx/active_support/inflector.rb +398 -0
- data/lib/jinx/cli/application.rb +36 -0
- data/lib/jinx/cli/command.rb +214 -0
- data/lib/jinx/helpers/array.rb +108 -0
- data/lib/jinx/helpers/boolean.rb +42 -0
- data/lib/jinx/helpers/case_insensitive_hash.rb +39 -0
- data/lib/jinx/helpers/class.rb +149 -0
- data/lib/jinx/helpers/collection.rb +33 -0
- data/lib/jinx/helpers/collections.rb +11 -0
- data/lib/jinx/helpers/collector.rb +20 -0
- data/lib/jinx/helpers/conditional_enumerator.rb +21 -0
- data/lib/jinx/helpers/enumerable.rb +242 -0
- data/lib/jinx/helpers/enumerate.rb +35 -0
- data/lib/jinx/helpers/error.rb +15 -0
- data/lib/jinx/helpers/file_separator.rb +65 -0
- data/lib/jinx/helpers/filter.rb +52 -0
- data/lib/jinx/helpers/flattener.rb +38 -0
- data/lib/jinx/helpers/hash.rb +12 -0
- data/lib/jinx/helpers/hashable.rb +502 -0
- data/lib/jinx/helpers/inflector.rb +36 -0
- data/lib/jinx/helpers/key_transformer_hash.rb +43 -0
- data/lib/jinx/helpers/lazy_hash.rb +44 -0
- data/lib/jinx/helpers/log.rb +106 -0
- data/lib/jinx/helpers/math.rb +12 -0
- data/lib/jinx/helpers/merge.rb +60 -0
- data/lib/jinx/helpers/module.rb +18 -0
- data/lib/jinx/helpers/multi_enumerator.rb +31 -0
- data/lib/jinx/helpers/options.rb +92 -0
- data/lib/jinx/helpers/os.rb +19 -0
- data/lib/jinx/helpers/partial_order.rb +37 -0
- data/lib/jinx/helpers/pretty_print.rb +207 -0
- data/lib/jinx/helpers/set.rb +8 -0
- data/lib/jinx/helpers/stopwatch.rb +76 -0
- data/lib/jinx/helpers/transformer.rb +24 -0
- data/lib/jinx/helpers/transitive_closure.rb +55 -0
- data/lib/jinx/helpers/uniquifier.rb +50 -0
- data/lib/jinx/helpers/validation.rb +33 -0
- data/lib/jinx/helpers/visitor.rb +370 -0
- data/lib/jinx/import/class_path_modifier.rb +77 -0
- data/lib/jinx/import/java.rb +337 -0
- data/lib/jinx/importer.rb +240 -0
- data/lib/jinx/metadata.rb +155 -0
- data/lib/jinx/metadata/attribute_enumerator.rb +73 -0
- data/lib/jinx/metadata/dependency.rb +244 -0
- data/lib/jinx/metadata/id_alias.rb +23 -0
- data/lib/jinx/metadata/introspector.rb +179 -0
- data/lib/jinx/metadata/inverse.rb +170 -0
- data/lib/jinx/metadata/java_property.rb +169 -0
- data/lib/jinx/metadata/propertied.rb +500 -0
- data/lib/jinx/metadata/property.rb +401 -0
- data/lib/jinx/metadata/property_characteristics.rb +114 -0
- data/lib/jinx/resource.rb +862 -0
- data/lib/jinx/resource/copy_visitor.rb +36 -0
- data/lib/jinx/resource/inversible.rb +90 -0
- data/lib/jinx/resource/match_visitor.rb +180 -0
- data/lib/jinx/resource/matcher.rb +20 -0
- data/lib/jinx/resource/merge_visitor.rb +73 -0
- data/lib/jinx/resource/mergeable.rb +185 -0
- data/lib/jinx/resource/reference_enumerator.rb +49 -0
- data/lib/jinx/resource/reference_path_visitor.rb +38 -0
- data/lib/jinx/resource/reference_visitor.rb +55 -0
- data/lib/jinx/resource/unique.rb +35 -0
- data/lib/jinx/version.rb +3 -0
- data/spec/defaults_spec.rb +30 -0
- data/spec/definitions/model/alias/child.rb +5 -0
- data/spec/definitions/model/base/child.rb +5 -0
- data/spec/definitions/model/base/domain_object.rb +5 -0
- data/spec/definitions/model/base/independent.rb +5 -0
- data/spec/definitions/model/defaults/child.rb +5 -0
- data/spec/definitions/model/dependency/child.rb +5 -0
- data/spec/definitions/model/dependency/parent.rb +6 -0
- data/spec/definitions/model/inverse/child.rb +5 -0
- data/spec/definitions/model/inverse/independent.rb +5 -0
- data/spec/definitions/model/inverse/parent.rb +5 -0
- data/spec/definitions/model/mandatory/child.rb +6 -0
- data/spec/dependency_spec.rb +47 -0
- data/spec/family_spec.rb +64 -0
- data/spec/inverse_spec.rb +53 -0
- data/spec/mandatory_spec.rb +43 -0
- data/spec/metadata_spec.rb +68 -0
- data/spec/resource_spec.rb +30 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/model.rb +19 -0
- data/test/fixtures/line_separator/cr_line_sep.txt +1 -0
- data/test/fixtures/line_separator/crlf_line_sep.txt +3 -0
- data/test/fixtures/line_separator/lf_line_sep.txt +3 -0
- data/test/fixtures/mixed/ext/build.xml +35 -0
- data/test/fixtures/mixed/ext/src/mixed/Case/Example.java +5 -0
- data/test/helper.rb +7 -0
- data/test/lib/jinx/command_test.rb +41 -0
- data/test/lib/jinx/helpers/boolean_test.rb +27 -0
- data/test/lib/jinx/helpers/class_test.rb +60 -0
- data/test/lib/jinx/helpers/collections_test.rb +402 -0
- data/test/lib/jinx/helpers/file_separator_test.rb +29 -0
- data/test/lib/jinx/helpers/inflector_test.rb +11 -0
- data/test/lib/jinx/helpers/lazy_hash_test.rb +32 -0
- data/test/lib/jinx/helpers/module_test.rb +24 -0
- data/test/lib/jinx/helpers/options_test.rb +66 -0
- data/test/lib/jinx/helpers/partial_order_test.rb +41 -0
- data/test/lib/jinx/helpers/pretty_print_test.rb +83 -0
- data/test/lib/jinx/helpers/stopwatch_test.rb +16 -0
- data/test/lib/jinx/helpers/transitive_closure_test.rb +80 -0
- data/test/lib/jinx/helpers/visitor_test.rb +288 -0
- data/test/lib/jinx/import/java_test.rb +78 -0
- data/test/lib/jinx/import/mixed_case_test.rb +16 -0
- metadata +272 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'rbconfig'
|
|
2
|
+
|
|
3
|
+
module Jinx
|
|
4
|
+
# Operating system methods.
|
|
5
|
+
module OS
|
|
6
|
+
include Config
|
|
7
|
+
|
|
8
|
+
# @return [System] the operating system type +:windows+, +:linux+, +:mac+, +:solaris+, or +:other+
|
|
9
|
+
def self.os_type
|
|
10
|
+
case CONFIG['host_os']
|
|
11
|
+
when /mswin|windows/i then :windows
|
|
12
|
+
when /linux/i then :linux
|
|
13
|
+
when /darwin/i then :mac
|
|
14
|
+
when /sunos|solaris/i then :solaris
|
|
15
|
+
else :other
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Jinx
|
|
2
|
+
# A PartialOrder is a Comparable which restricted scope. Classes which include PartialOrder
|
|
3
|
+
# are required to implement the <=> operator with the following semantics:
|
|
4
|
+
# * _a_ <=> _b_ returns -1, 0, or 1 if a and b are comparable, nil otherwise
|
|
5
|
+
# A PartialOrder thus relaxes comparison symmetry, e.g.
|
|
6
|
+
# a < b
|
|
7
|
+
# does not imply
|
|
8
|
+
# b >= a.
|
|
9
|
+
# Example:
|
|
10
|
+
# module Queued
|
|
11
|
+
# attr_reader :queue
|
|
12
|
+
# def <=>(other)
|
|
13
|
+
# queue.index(self) <=> queue.index(other) if queue.equal?(other.queue)
|
|
14
|
+
# end
|
|
15
|
+
# end
|
|
16
|
+
# q1 = [a, b] # a, b are Queued
|
|
17
|
+
# q2 = [c] # c is a Queued
|
|
18
|
+
# a < b #=> true
|
|
19
|
+
# b < c #=> nil
|
|
20
|
+
module PartialOrder
|
|
21
|
+
include Comparable
|
|
22
|
+
|
|
23
|
+
Comparable.instance_methods(false).each do |m|
|
|
24
|
+
define_method(m.to_sym) do |other|
|
|
25
|
+
self <=> other ? super : nil
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @return [Boolean] true if other is an instance of this object's class and other == self,
|
|
30
|
+
# false otherwise
|
|
31
|
+
def eql?(other)
|
|
32
|
+
self.class === other and super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
alias :== :eql?
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
require 'date'
|
|
3
|
+
require 'pp'
|
|
4
|
+
require 'stringio'
|
|
5
|
+
require 'jinx/helpers/options'
|
|
6
|
+
require 'jinx/helpers/collections'
|
|
7
|
+
|
|
8
|
+
require 'jinx/helpers/inflector'
|
|
9
|
+
|
|
10
|
+
class PrettyPrint
|
|
11
|
+
# The standard +prettyprint+ gem SingleLine is adjusted to add an output accessor and an optional output argument to {#initialize}.
|
|
12
|
+
class SingleLine
|
|
13
|
+
# @return [String] the print target
|
|
14
|
+
attr_reader :output
|
|
15
|
+
|
|
16
|
+
alias :base__initialize :initialize
|
|
17
|
+
private :base__initialize
|
|
18
|
+
|
|
19
|
+
# Overrides the standard SingleLine initializer to supply an output parameter default.
|
|
20
|
+
def initialize(output='', maxwidth=nil, newline=nil)
|
|
21
|
+
base__initialize(output, maxwidth, newline)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# A PrintWrapper prints arguments by calling a printer proc.
|
|
27
|
+
class PrintWrapper < Proc
|
|
28
|
+
# Creates a new PrintWrapper on the given arguments.
|
|
29
|
+
def initialize(*args)
|
|
30
|
+
super()
|
|
31
|
+
@args = args
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @param args this wrapper's print block parameters
|
|
35
|
+
# @return [PrintWrapper] self
|
|
36
|
+
def wrap(*args)
|
|
37
|
+
@args = args
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Calls this PrintWrapper's print procedure on the arguments set in the initializer.
|
|
42
|
+
def to_s
|
|
43
|
+
@args.empty? ? 'nil' : call(*@args)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
alias :inspect :to_s
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class Object
|
|
50
|
+
# @return [String] this object's class demodulized name and object id
|
|
51
|
+
def print_class_and_id
|
|
52
|
+
"#{self.class.qp}@#{object_id}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# qp, an abbreviation for quick-print, calls {#print_class_and_id} in this base implementation.
|
|
56
|
+
alias :qp :print_class_and_id
|
|
57
|
+
|
|
58
|
+
# Formats this object with the standard {PrettyPrint}.
|
|
59
|
+
#
|
|
60
|
+
# @param [Hash, Symbol, nil] opts the print options
|
|
61
|
+
# @option opts [Boolean] :single_line print the output on a single line
|
|
62
|
+
# @return [String] the formatted print result
|
|
63
|
+
def pp_s(opts=nil)
|
|
64
|
+
s = StringIO.new
|
|
65
|
+
if Options.get(:single_line, opts) then
|
|
66
|
+
PP.singleline_pp(self, s)
|
|
67
|
+
else
|
|
68
|
+
PP.pp(self, s)
|
|
69
|
+
end
|
|
70
|
+
s.rewind
|
|
71
|
+
s.read.chomp
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class Numeric
|
|
76
|
+
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
|
77
|
+
alias :qp :to_s
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class String
|
|
81
|
+
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
|
82
|
+
alias :qp :to_s
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class TrueClass
|
|
86
|
+
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
|
87
|
+
alias :qp :to_s
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class FalseClass
|
|
91
|
+
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
|
92
|
+
alias :qp :to_s
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class NilClass
|
|
96
|
+
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
|
97
|
+
alias :qp :inspect
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class Symbol
|
|
101
|
+
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
|
102
|
+
alias :qp :inspect
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class Module
|
|
106
|
+
# @return [String ] the demodulized name
|
|
107
|
+
def qp
|
|
108
|
+
name[/\w+$/]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
module Enumerable
|
|
113
|
+
# Prints this Enumerable with a filter that calls qp on each item.
|
|
114
|
+
# Non-collection Enumerable classes override this method to delegate to {Object#qp}.
|
|
115
|
+
#
|
|
116
|
+
# Unlike {Object#qp}, this implementation accepts the {Object#pp_s} options.
|
|
117
|
+
# The options are used to format this Enumerable, but are not propagated to the
|
|
118
|
+
# enumerated items.
|
|
119
|
+
#
|
|
120
|
+
# @param (see Object#pp_s)
|
|
121
|
+
# @return [String] the formatted result
|
|
122
|
+
def qp(opts=nil)
|
|
123
|
+
wrap { |item| item.qp }.pp_s(opts)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# If a transformer block is given to this method, then the block is applied to each
|
|
127
|
+
# enumerated item before pretty-printing the result.
|
|
128
|
+
#
|
|
129
|
+
# @param (see Object#pp_s)
|
|
130
|
+
# @yield [item] transforms the item to print
|
|
131
|
+
# @yieldparam item the item to print
|
|
132
|
+
# @return (see Oblect#pp_s)
|
|
133
|
+
def pp_s(opts=nil)
|
|
134
|
+
# delegate to Object if no block
|
|
135
|
+
return super unless block_given?
|
|
136
|
+
# make a print wrapper
|
|
137
|
+
wrapper = PrintWrapper.new { |item| yield item }
|
|
138
|
+
# print using the wrapper on each item
|
|
139
|
+
wrap { |item| wrapper.wrap(item) }.pp_s(opts)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Pretty-prints the content within brackets, as is done by the Array pretty printer.
|
|
143
|
+
def pretty_print(q)
|
|
144
|
+
q.group(1, '[', ']') {
|
|
145
|
+
q.seplist(self) { |v|
|
|
146
|
+
q.pp v
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Pretty-prints the cycle within brackets, as is done by the Array pretty printer.
|
|
152
|
+
def pretty_print_cycle(q)
|
|
153
|
+
q.text(empty? ? '[]' : '[...]')
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
module Jinx
|
|
158
|
+
module Hashable
|
|
159
|
+
# qp, short for quick-print, prints this Hashable with a filter that calls qp on each key and value.
|
|
160
|
+
#
|
|
161
|
+
# @return [String] the quick-print result
|
|
162
|
+
def qp
|
|
163
|
+
qph = {}
|
|
164
|
+
each { |k, v| qph[k.qp] = v.qp }
|
|
165
|
+
qph.pp_s
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def pretty_print(q)
|
|
169
|
+
Hash === self ? q.pp_hash(self) : q.pp_hash(to_hash)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def pretty_print_cycle(q)
|
|
173
|
+
q.text(empty? ? '{}' : '{...}')
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
class String
|
|
179
|
+
# Pretty-prints this String using the Object pretty_print rather than Enumerable pretty_print.
|
|
180
|
+
def pretty_print(q)
|
|
181
|
+
q.text self
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
class DateTime
|
|
186
|
+
# @return [String] the formatted +strftime+
|
|
187
|
+
def pretty_print(q)
|
|
188
|
+
q.text(strftime)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# qp, an abbreviation for quick-print, is an alias for {#to_s} in this primitive class.
|
|
192
|
+
alias :qp :to_s
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
class Set
|
|
196
|
+
# Formats this set using {Enumerable#pretty_print}.
|
|
197
|
+
def pretty_print(q)
|
|
198
|
+
# mark this object as visited; this fragment is inferred from pp.rb and is necessary to detect a cycle
|
|
199
|
+
Thread.current[:__inspect_key__] << __id__
|
|
200
|
+
to_a.pretty_print(q)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# The pp.rb default pretty printing method for general objects that are detected as part of a cycle.
|
|
204
|
+
def pretty_print_cycle(q)
|
|
205
|
+
to_a.pretty_print_cycle(q)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
class Set
|
|
4
|
+
# The standard Set {#merge} is an anomaly among Ruby collections, since merge modifies the called Set in-place rather
|
|
5
|
+
# than return a new Set containing the merged contents. Preserve this unfortunate behavior, but partially address
|
|
6
|
+
# the anomaly by adding the merge! alias to make it clear that this is an in-place merge.
|
|
7
|
+
alias :merge! :merge
|
|
8
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'benchmark'
|
|
2
|
+
|
|
3
|
+
module Jinx
|
|
4
|
+
# Stopwatch is a simple execution time accumulator.
|
|
5
|
+
class Stopwatch
|
|
6
|
+
# Time accumulates elapsed real time and total CPU time.
|
|
7
|
+
class Time
|
|
8
|
+
# @return [Benchmark::Tms] the Tms wrapped by this Time
|
|
9
|
+
attr_reader :tms
|
|
10
|
+
|
|
11
|
+
# @param [Benchmark::Tms, nil] the starting time (default is now)
|
|
12
|
+
def initialize(tms=nil)
|
|
13
|
+
@tms = tms || Benchmark::Tms.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [Numeric] the cumulative elapsed real clock time
|
|
17
|
+
def elapsed
|
|
18
|
+
@tms.real
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Numeric] the cumulative CPU total time
|
|
22
|
+
def cpu
|
|
23
|
+
@tms.total
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Adds the time to execute the given block to this time.
|
|
27
|
+
#
|
|
28
|
+
# @return [Numeric] the split execution Time
|
|
29
|
+
def split(&block)
|
|
30
|
+
stms = Benchmark.measure(&block)
|
|
31
|
+
@tms += stms
|
|
32
|
+
Time.new(stms)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Sets this benchmark timer to zero.
|
|
36
|
+
def reset
|
|
37
|
+
@tms = Benchmark::Tms.new
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Executes the given block
|
|
42
|
+
#
|
|
43
|
+
# @return [Numeric] the execution Time
|
|
44
|
+
def self.measure(&block)
|
|
45
|
+
new.run(&block)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Creates a new idle Stopwatch.
|
|
49
|
+
def initialize
|
|
50
|
+
@time = Time.new
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Executes the given block. Accumulates the execution time in this Stopwatch.
|
|
54
|
+
#
|
|
55
|
+
# @return [Numeric] the execution run Time
|
|
56
|
+
def run(&block)
|
|
57
|
+
@time.split(&block)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Numeric] the cumulative elapsed real clock time spent in {#run} executions
|
|
61
|
+
def elapsed
|
|
62
|
+
@time.elapsed
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [Numeric] the cumulative CPU total time spent in {#run} executions for the
|
|
66
|
+
# current process and its children
|
|
67
|
+
def cpu
|
|
68
|
+
@time.cpu
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Resets this Stopwatch's cumulative time to zero.
|
|
72
|
+
def reset
|
|
73
|
+
@time.reset
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Jinx
|
|
2
|
+
# This Transformer helper class applies a transformer block to a base enumeration.
|
|
3
|
+
class Transformer
|
|
4
|
+
include Collection
|
|
5
|
+
|
|
6
|
+
def initialize(enum=[], &transformer)
|
|
7
|
+
@base = enum
|
|
8
|
+
@xfm = transformer
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Sets the base Enumerable on which this Transformer operates and returns this transformer, e.g.:
|
|
12
|
+
# transformer = Transformer.new { |n| n * 2 }
|
|
13
|
+
# transformer.on([1, 2, 3]).to_a #=> [2, 4, 6]
|
|
14
|
+
def on(enum)
|
|
15
|
+
@base = enum
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Calls the block on each item after this Transformer's transformer block is applied.
|
|
20
|
+
def each
|
|
21
|
+
@base.each { |item| yield(item.nil? ? nil : @xfm.call(item)) }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'jinx/helpers/visitor'
|
|
2
|
+
|
|
3
|
+
class Object
|
|
4
|
+
# Returns the transitive closure over a method or block. This method returns an array partially ordered
|
|
5
|
+
# by the children method or block, i.e. each node occurs before all other nodes referenced directly or
|
|
6
|
+
# indirectly by the children.
|
|
7
|
+
#
|
|
8
|
+
# If a method symbol or name is provided, then that method is called. Otherwise, the block is called.
|
|
9
|
+
# In either case, the call is expected to return an object or Enumerable of objects which also respond
|
|
10
|
+
# to the method or block.
|
|
11
|
+
#
|
|
12
|
+
# @param [Symbol, nil] method the child reference, or nil if a block is given
|
|
13
|
+
# @yield [node] the parent node's children
|
|
14
|
+
# @yieldparam node the parent node
|
|
15
|
+
# @example
|
|
16
|
+
# class Node
|
|
17
|
+
# attr_reader :parent, :children
|
|
18
|
+
# def initialize(name, parent=nil)
|
|
19
|
+
# super()
|
|
20
|
+
# @name = name
|
|
21
|
+
# @parent = parent
|
|
22
|
+
# @children = []
|
|
23
|
+
# parent.children << self if parent
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# def to_s;
|
|
27
|
+
# end
|
|
28
|
+
# a = Node.new('a'); b = Node.new('b', a), c = Node.new('c', a); d = Node.new('d', c)
|
|
29
|
+
# a.transitive_closure { |node| node.children }.to_a.join(", ") #=> a, b, c, d
|
|
30
|
+
# a.transitive_closure(:children).to_a.join(", ") #=> a, b, c, d
|
|
31
|
+
def transitive_closure(method=nil)
|
|
32
|
+
Jinx.fail(ArgumentError, "Missing both a method argument and a block") if method.nil? and not block_given?
|
|
33
|
+
# If there is a method argument, then the transitive closure is based on that method.
|
|
34
|
+
# Otherwise, visit the closure in reverse depth-first order.
|
|
35
|
+
if method then
|
|
36
|
+
transitive_closure() { |node| node.send(method) }
|
|
37
|
+
else
|
|
38
|
+
Jinx::Visitor.new(:depth_first) { |node| yield node }.to_enum(self).to_a.reverse
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
module Enumerable
|
|
44
|
+
# Returns the transitive closure over all items in this Enumerable.
|
|
45
|
+
#
|
|
46
|
+
# @see Object#transitive_closure
|
|
47
|
+
def transitive_closure(method=nil)
|
|
48
|
+
# delegate to Object if there is a method argument
|
|
49
|
+
return super(method) if method
|
|
50
|
+
# this Enumerable's children are this Enumerable's contents
|
|
51
|
+
closure = super() { |node| node.equal?(self) ? self : yield(node) }
|
|
52
|
+
# remove this collection from the closure
|
|
53
|
+
closure[1..-1]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
require 'jinx/helpers/lazy_hash'
|
|
3
|
+
|
|
4
|
+
module Jinx
|
|
5
|
+
# A utility class to generate value qualifiers.
|
|
6
|
+
class Uniquifier
|
|
7
|
+
include Singleton
|
|
8
|
+
|
|
9
|
+
# Returns a relatively unique integral qualifier. Successive calls to this method
|
|
10
|
+
# within the same time zone spaced more than a millisecond apart return different
|
|
11
|
+
# integers. Each generated qualifier is greater than the previous by an unspecified
|
|
12
|
+
# amount.
|
|
13
|
+
def self.qualifier
|
|
14
|
+
# the first date that this method could be called
|
|
15
|
+
@first ||= Date.new(2011, 12, 01)
|
|
16
|
+
# days as integer + milliseconds as fraction since the first date
|
|
17
|
+
diff = DateTime.now - @first
|
|
18
|
+
# shift a tenth of a milli up into the integer portion
|
|
19
|
+
decimillis = diff * 24 * 60 * 60 * 10000
|
|
20
|
+
# truncate the fraction
|
|
21
|
+
decimillis.truncate
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
@cache = Jinx::LazyHash.new { Hash.new }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @param obj the object containing the value
|
|
29
|
+
# @param value the value to make unique
|
|
30
|
+
# @return the new unique value, or nil if the given value is nil
|
|
31
|
+
def uniquify(obj, value)
|
|
32
|
+
@cache[obj.class][value] ||= value.uniquify if value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def clear
|
|
36
|
+
@cache.clear
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class String
|
|
42
|
+
# Returns a relatively unique value obtained from the specified base value.
|
|
43
|
+
# The suffix is generated by {Jinx::Uniquifier.qualifier}. Spaces are removed.
|
|
44
|
+
#
|
|
45
|
+
# @example
|
|
46
|
+
# 'Test Name'.uniquify #=> Test_Name_330938800614
|
|
47
|
+
def uniquify
|
|
48
|
+
gsub(' ', '_') + "_#{Jinx::Uniquifier.qualifier}"
|
|
49
|
+
end
|
|
50
|
+
end
|