skylight 0.2.7 → 0.3.0.rc.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/checksums.yml +3 -0
- data/ext/extconf.rb +90 -0
- data/ext/skylight.map +4 -0
- data/ext/skylight_native.c +613 -0
- data/lib/skylight.rb +50 -7
- data/lib/skylight/config.rb +7 -1
- data/lib/skylight/helpers.rb +2 -2
- data/lib/skylight/instrumenter.rb +9 -5
- data/lib/skylight/messages.rb +13 -13
- data/lib/skylight/messages/error.rb +10 -6
- data/lib/skylight/messages/hello.rb +4 -45
- data/lib/skylight/messages/trace.rb +62 -103
- data/lib/skylight/messages/trace_envelope.rb +19 -0
- data/lib/skylight/native.rb +80 -0
- data/lib/skylight/normalizers/process_action.rb +1 -3
- data/lib/skylight/probes.rb +1 -1
- data/lib/skylight/subscriber.rb +1 -1
- data/lib/skylight/util/clock.rb +13 -6
- data/lib/skylight/version.rb +1 -1
- data/lib/skylight/worker/builder.rb +1 -1
- data/lib/skylight/worker/collector.rb +20 -32
- data/lib/skylight/worker/connection.rb +2 -2
- data/lib/skylight/worker/embedded.rb +18 -0
- data/lib/skylight/worker/server.rb +3 -3
- data/lib/skylight/worker/standalone.rb +9 -10
- data/lib/sql_lexer.rb +0 -1
- data/lib/sql_lexer/lexer.rb +50 -4
- data/lib/sql_lexer/version.rb +1 -1
- metadata +19 -22
- data/lib/skylight/messages/annotation.rb +0 -13
- data/lib/skylight/messages/base.rb +0 -24
- data/lib/skylight/messages/batch.rb +0 -12
- data/lib/skylight/messages/endpoint.rb +0 -12
- data/lib/skylight/messages/event.rb +0 -12
- data/lib/skylight/messages/span.rb +0 -166
- data/lib/skylight/vendor/beefcake.rb +0 -292
- data/lib/skylight/vendor/beefcake/buffer.rb +0 -119
- data/lib/skylight/vendor/beefcake/decode.rb +0 -107
- data/lib/skylight/vendor/beefcake/encode.rb +0 -132
data/lib/sql_lexer/version.rb
CHANGED
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skylight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0.rc.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tilde, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 3.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 3.0.0
|
27
27
|
description:
|
@@ -29,9 +29,17 @@ email:
|
|
29
29
|
- engineering@tilde.io
|
30
30
|
executables:
|
31
31
|
- skylight
|
32
|
-
extensions:
|
32
|
+
extensions:
|
33
|
+
- ext/extconf.rb
|
33
34
|
extra_rdoc_files: []
|
34
35
|
files:
|
36
|
+
- CHANGELOG.md
|
37
|
+
- README.md
|
38
|
+
- bin/skylight
|
39
|
+
- ext/checksums.yml
|
40
|
+
- ext/extconf.rb
|
41
|
+
- ext/skylight.map
|
42
|
+
- ext/skylight_native.c
|
35
43
|
- lib/skylight.rb
|
36
44
|
- lib/skylight/api.rb
|
37
45
|
- lib/skylight/cli.rb
|
@@ -43,16 +51,12 @@ files:
|
|
43
51
|
- lib/skylight/helpers.rb
|
44
52
|
- lib/skylight/instrumenter.rb
|
45
53
|
- lib/skylight/messages.rb
|
46
|
-
- lib/skylight/messages/annotation.rb
|
47
|
-
- lib/skylight/messages/base.rb
|
48
|
-
- lib/skylight/messages/batch.rb
|
49
|
-
- lib/skylight/messages/endpoint.rb
|
50
54
|
- lib/skylight/messages/error.rb
|
51
|
-
- lib/skylight/messages/event.rb
|
52
55
|
- lib/skylight/messages/hello.rb
|
53
|
-
- lib/skylight/messages/span.rb
|
54
56
|
- lib/skylight/messages/trace.rb
|
57
|
+
- lib/skylight/messages/trace_envelope.rb
|
55
58
|
- lib/skylight/middleware.rb
|
59
|
+
- lib/skylight/native.rb
|
56
60
|
- lib/skylight/normalizers.rb
|
57
61
|
- lib/skylight/normalizers/default.rb
|
58
62
|
- lib/skylight/normalizers/moped.rb
|
@@ -81,10 +85,6 @@ files:
|
|
81
85
|
- lib/skylight/vendor/active_support/notifications/fanout.rb
|
82
86
|
- lib/skylight/vendor/active_support/notifications/instrumenter.rb
|
83
87
|
- lib/skylight/vendor/active_support/per_thread_registry.rb
|
84
|
-
- lib/skylight/vendor/beefcake.rb
|
85
|
-
- lib/skylight/vendor/beefcake/buffer.rb
|
86
|
-
- lib/skylight/vendor/beefcake/decode.rb
|
87
|
-
- lib/skylight/vendor/beefcake/encode.rb
|
88
88
|
- lib/skylight/vendor/cli/highline.rb
|
89
89
|
- lib/skylight/vendor/cli/highline/color_scheme.rb
|
90
90
|
- lib/skylight/vendor/cli/highline/compatibility.rb
|
@@ -139,9 +139,6 @@ files:
|
|
139
139
|
- lib/sql_lexer.rb
|
140
140
|
- lib/sql_lexer/lexer.rb
|
141
141
|
- lib/sql_lexer/version.rb
|
142
|
-
- CHANGELOG.md
|
143
|
-
- README.md
|
144
|
-
- bin/skylight
|
145
142
|
homepage: http://www.skylight.io
|
146
143
|
licenses: []
|
147
144
|
metadata: {}
|
@@ -151,17 +148,17 @@ require_paths:
|
|
151
148
|
- lib
|
152
149
|
required_ruby_version: !ruby/object:Gem::Requirement
|
153
150
|
requirements:
|
154
|
-
- -
|
151
|
+
- - ">="
|
155
152
|
- !ruby/object:Gem::Version
|
156
153
|
version: 1.9.2
|
157
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
155
|
requirements:
|
159
|
-
- -
|
156
|
+
- - ">"
|
160
157
|
- !ruby/object:Gem::Version
|
161
|
-
version:
|
158
|
+
version: 1.3.1
|
162
159
|
requirements: []
|
163
160
|
rubyforge_project:
|
164
|
-
rubygems_version: 2.0
|
161
|
+
rubygems_version: 2.2.0
|
165
162
|
signing_key:
|
166
163
|
specification_version: 4
|
167
164
|
summary: Skylight is a ruby application monitoring tool. Currently in closed beta.
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Messages
|
3
|
-
class Annotation
|
4
|
-
include Beefcake::Message
|
5
|
-
|
6
|
-
optional :key, :string, 1
|
7
|
-
optional :int, :int64, 2
|
8
|
-
optional :double, :double, 3
|
9
|
-
optional :string, :string, 4
|
10
|
-
repeated :nested, Annotation, 5
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Messages
|
3
|
-
class Base
|
4
|
-
module ClassMethods
|
5
|
-
attr_accessor :message_id
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.inherited(klass)
|
9
|
-
klass.class_eval do
|
10
|
-
include Beefcake::Message
|
11
|
-
extend ClassMethods
|
12
|
-
end
|
13
|
-
|
14
|
-
klass.message_id = (@count ||= 0)
|
15
|
-
Messages.set(klass.message_id, klass)
|
16
|
-
@count += 1
|
17
|
-
end
|
18
|
-
|
19
|
-
def message_id
|
20
|
-
self.class.message_id
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,166 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Messages
|
3
|
-
class AnnotationBuilder
|
4
|
-
def self.build(object)
|
5
|
-
new(object).build
|
6
|
-
end
|
7
|
-
|
8
|
-
def initialize(object)
|
9
|
-
@object = object
|
10
|
-
end
|
11
|
-
|
12
|
-
def build
|
13
|
-
build_nested(@object)
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
def build_nested(object)
|
18
|
-
case object
|
19
|
-
when Hash
|
20
|
-
build_hash(object)
|
21
|
-
when Array
|
22
|
-
build_array(object)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def build_hash(object)
|
27
|
-
object.map do |key, value|
|
28
|
-
build_annotation(value, key)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def build_array(array)
|
33
|
-
array.map do |value|
|
34
|
-
build_annotation(value)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def build_annotation(value, key=nil)
|
39
|
-
Annotation.new.tap do |annotation|
|
40
|
-
annotation.key = key.to_s if key
|
41
|
-
annotation[classify(value)] = build_value(value)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def build_value(value)
|
46
|
-
nested?(value) ? build_nested(value) : value
|
47
|
-
end
|
48
|
-
|
49
|
-
def nested?(value)
|
50
|
-
value.is_a?(Array) || value.is_a?(Hash)
|
51
|
-
end
|
52
|
-
|
53
|
-
def classify(value)
|
54
|
-
case value
|
55
|
-
when String
|
56
|
-
:string
|
57
|
-
when Integer
|
58
|
-
:int
|
59
|
-
when Numeric
|
60
|
-
:double
|
61
|
-
when Hash, Array
|
62
|
-
:nested
|
63
|
-
else
|
64
|
-
raise Skylight::SerializeError.new("Annotation values must be Strings or Numeric. You passed #{value.inspect} in #{@object.inspect}")
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class Span
|
70
|
-
include Beefcake::Message
|
71
|
-
|
72
|
-
required :event, Event, 1
|
73
|
-
repeated :annotations, Annotation, 2
|
74
|
-
required :started_at, :uint32, 3
|
75
|
-
optional :duration, :uint32, 4
|
76
|
-
optional :children, :uint32, 5
|
77
|
-
|
78
|
-
# Bit of a hack
|
79
|
-
attr_accessor :absolute_time
|
80
|
-
|
81
|
-
# Optimization
|
82
|
-
def initialize(attrs = nil)
|
83
|
-
super if attrs
|
84
|
-
end
|
85
|
-
|
86
|
-
class Builder
|
87
|
-
|
88
|
-
include Util::Logging
|
89
|
-
|
90
|
-
attr_reader \
|
91
|
-
:time,
|
92
|
-
:category,
|
93
|
-
:title,
|
94
|
-
:started_at,
|
95
|
-
:description,
|
96
|
-
:annotations
|
97
|
-
|
98
|
-
attr_accessor :children
|
99
|
-
|
100
|
-
def initialize(trace, time, started_at, cat, title, desc, annot)
|
101
|
-
@trace = trace
|
102
|
-
@built = false
|
103
|
-
@time = time
|
104
|
-
@started_at = started_at
|
105
|
-
@category = cat.to_s
|
106
|
-
@children = 0
|
107
|
-
@annotations = annot
|
108
|
-
|
109
|
-
self.title = title
|
110
|
-
self.description = desc
|
111
|
-
end
|
112
|
-
|
113
|
-
def config
|
114
|
-
@trace.config
|
115
|
-
end
|
116
|
-
|
117
|
-
def endpoint=(name)
|
118
|
-
@trace.endpoint = name
|
119
|
-
end
|
120
|
-
|
121
|
-
def done
|
122
|
-
@trace.done(self) unless built?
|
123
|
-
rescue Exception => e
|
124
|
-
error e.message
|
125
|
-
t { e.backtrace.join("\n") }
|
126
|
-
end
|
127
|
-
|
128
|
-
def built?
|
129
|
-
@built
|
130
|
-
end
|
131
|
-
|
132
|
-
def build(duration)
|
133
|
-
@built = true
|
134
|
-
Span.new(
|
135
|
-
event: Event.new(
|
136
|
-
category: category,
|
137
|
-
title: title,
|
138
|
-
description: description),
|
139
|
-
annotations: nil,
|
140
|
-
started_at: @started_at,
|
141
|
-
duration: duration && duration > 0 ? duration : nil,
|
142
|
-
children: @children > 0 ? @children : nil)
|
143
|
-
end
|
144
|
-
|
145
|
-
def title=(val)
|
146
|
-
val = nil unless val.respond_to?(:to_str)
|
147
|
-
@title = val && val.to_str
|
148
|
-
end
|
149
|
-
|
150
|
-
def description=(val)
|
151
|
-
val = nil unless val.respond_to?(:to_str)
|
152
|
-
@description = val && val.to_str
|
153
|
-
end
|
154
|
-
|
155
|
-
private
|
156
|
-
|
157
|
-
def to_annotations(val)
|
158
|
-
return nil if !val || val.empty?
|
159
|
-
|
160
|
-
AnnotationBuilder.build(val)
|
161
|
-
end
|
162
|
-
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
@@ -1,292 +0,0 @@
|
|
1
|
-
require 'skylight/vendor/beefcake/encode'
|
2
|
-
require 'skylight/vendor/beefcake/decode'
|
3
|
-
|
4
|
-
module Skylight
|
5
|
-
module Beefcake
|
6
|
-
module Message
|
7
|
-
|
8
|
-
class WrongTypeError < StandardError
|
9
|
-
def initialize(name, exp, got)
|
10
|
-
super("Wrong type `#{got}` given for (#{name}). Expected #{exp}")
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
|
15
|
-
class InvalidValueError < StandardError
|
16
|
-
def initialize(name, val)
|
17
|
-
super("Invalid Value given for `#{name}`: #{val.inspect}")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
class RequiredFieldNotSetError < StandardError
|
23
|
-
def initialize(name)
|
24
|
-
super("Field #{name} is required but nil")
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
class Field < Struct.new(:rule, :name, :type, :fn, :opts)
|
30
|
-
def <=>(o)
|
31
|
-
fn <=> o.fn
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
module Dsl
|
37
|
-
def self.extended(base)
|
38
|
-
initializer = Module.new
|
39
|
-
base.instance_variable_set(:@__initializer, initializer)
|
40
|
-
base.__write_initializer
|
41
|
-
base.send(:include, initializer)
|
42
|
-
end
|
43
|
-
|
44
|
-
def required(name, type, fn, opts={})
|
45
|
-
field(:required, name, type, fn, opts)
|
46
|
-
end
|
47
|
-
|
48
|
-
def repeated(name, type, fn, opts={})
|
49
|
-
field(:repeated, name, type, fn, opts)
|
50
|
-
end
|
51
|
-
|
52
|
-
def optional(name, type, fn, opts={})
|
53
|
-
field(:optional, name, type, fn, opts)
|
54
|
-
end
|
55
|
-
|
56
|
-
def field(rule, name, type, fn, opts)
|
57
|
-
field = Field.new(rule, name, type, fn, opts)
|
58
|
-
indexed_fields[fn] = field
|
59
|
-
fields << field
|
60
|
-
fields.sort!
|
61
|
-
__write_initializer
|
62
|
-
attr_accessor name
|
63
|
-
end
|
64
|
-
|
65
|
-
def fields
|
66
|
-
@fields ||= []
|
67
|
-
end
|
68
|
-
|
69
|
-
def indexed_fields
|
70
|
-
@indexed_fields ||= {}
|
71
|
-
end
|
72
|
-
|
73
|
-
def __write_initializer
|
74
|
-
lines = []
|
75
|
-
|
76
|
-
lines << "def initialize(attrs=nil)"
|
77
|
-
lines << "return unless attrs"
|
78
|
-
fields.each do |fld|
|
79
|
-
lines << "@#{fld.name} = attrs[:#{fld.name}]"
|
80
|
-
end
|
81
|
-
|
82
|
-
lines << "end"
|
83
|
-
|
84
|
-
@__initializer.module_eval(lines.join("\n"), __FILE__, __LINE__+1)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
module Encode
|
89
|
-
|
90
|
-
def encode(buf = Buffer.new)
|
91
|
-
validate!
|
92
|
-
|
93
|
-
if ! buf.respond_to?(:<<)
|
94
|
-
raise ArgumentError, "buf doesn't respond to `<<`"
|
95
|
-
end
|
96
|
-
|
97
|
-
if ! buf.is_a?(Buffer)
|
98
|
-
buf = Buffer.new(buf)
|
99
|
-
end
|
100
|
-
|
101
|
-
# TODO: Error if any required fields at nil
|
102
|
-
|
103
|
-
fields.each do |fld|
|
104
|
-
if fld.opts[:packed]
|
105
|
-
bytes = encode!(Buffer.new, fld, 0)
|
106
|
-
buf.append_info(fld.fn, Buffer.wire_for(fld.type))
|
107
|
-
buf.append_uint64(bytes.length)
|
108
|
-
buf << bytes
|
109
|
-
else
|
110
|
-
encode!(buf, fld, fld.fn)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
buf
|
115
|
-
end
|
116
|
-
|
117
|
-
def encode!(buf, fld, fn)
|
118
|
-
v = self[fld.name]
|
119
|
-
|
120
|
-
if v.is_a?(Array)
|
121
|
-
v.each do |val|
|
122
|
-
encode_field!(buf, fld.type, val, fn)
|
123
|
-
end
|
124
|
-
else
|
125
|
-
encode_field!(buf, fld.type, v, fn)
|
126
|
-
end
|
127
|
-
|
128
|
-
buf
|
129
|
-
end
|
130
|
-
|
131
|
-
def encode_field!(buf, type, val, fn)
|
132
|
-
return if val.nil?
|
133
|
-
|
134
|
-
case type
|
135
|
-
when Class # encodable
|
136
|
-
# TODO: raise error if type != val.class
|
137
|
-
buf.append(:string, val.encode, fn)
|
138
|
-
when Module # enum
|
139
|
-
if ! valid_enum?(type, val)
|
140
|
-
raise InvalidValueError.new(fld.name, val)
|
141
|
-
end
|
142
|
-
|
143
|
-
buf.append(:int32, val, fn)
|
144
|
-
else
|
145
|
-
buf.append(type, val, fn)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def valid_enum?(mod, val)
|
150
|
-
!!name_for(mod, val)
|
151
|
-
end
|
152
|
-
|
153
|
-
def name_for(mod, val)
|
154
|
-
mod.constants.each do |name|
|
155
|
-
if mod.const_get(name) == val
|
156
|
-
return name
|
157
|
-
end
|
158
|
-
end
|
159
|
-
nil
|
160
|
-
end
|
161
|
-
|
162
|
-
def validate!
|
163
|
-
fields.each do |fld|
|
164
|
-
if fld.rule == :required && self[fld.name].nil?
|
165
|
-
raise RequiredFieldNotSetError, fld.name
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
|
172
|
-
module Decode
|
173
|
-
# Use allocate instead of new for performance
|
174
|
-
def decode(buf, o=self.allocate)
|
175
|
-
if ! buf.is_a?(Buffer)
|
176
|
-
buf = Buffer.new(buf)
|
177
|
-
end
|
178
|
-
|
179
|
-
# TODO: test for incomplete buffer
|
180
|
-
while buf.length > 0
|
181
|
-
fn, wire = buf.read_info
|
182
|
-
|
183
|
-
fld = indexed_fields[fn]
|
184
|
-
|
185
|
-
# We don't have a field for with index fn.
|
186
|
-
# Ignore this data and move on.
|
187
|
-
if fld.nil?
|
188
|
-
buf.skip(wire)
|
189
|
-
next
|
190
|
-
end
|
191
|
-
|
192
|
-
exp = Buffer.wire_for(fld.type)
|
193
|
-
if wire != exp
|
194
|
-
raise WrongTypeError.new(fld.name, exp, wire)
|
195
|
-
end
|
196
|
-
|
197
|
-
if fld.rule == :repeated && fld.opts[:packed]
|
198
|
-
len = buf.read_uint64
|
199
|
-
tmp = Buffer.new(buf.read(len))
|
200
|
-
o[fld.name] ||= []
|
201
|
-
while tmp.length > 0
|
202
|
-
o[fld.name] << tmp.read(fld.type)
|
203
|
-
end
|
204
|
-
elsif fld.rule == :repeated
|
205
|
-
val = buf.read(fld.type)
|
206
|
-
(o[fld.name] ||= []) << val
|
207
|
-
else
|
208
|
-
val = buf.read(fld.type)
|
209
|
-
o[fld.name] = val
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
# Set defaults
|
214
|
-
fields.each do |f|
|
215
|
-
next if o[f.name] == false
|
216
|
-
o[f.name] ||= f.opts[:default]
|
217
|
-
end
|
218
|
-
|
219
|
-
o.validate!
|
220
|
-
|
221
|
-
o
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
|
226
|
-
def self.included(o)
|
227
|
-
o.extend Dsl
|
228
|
-
o.extend Decode
|
229
|
-
o.send(:include, Encode)
|
230
|
-
end
|
231
|
-
|
232
|
-
def fields
|
233
|
-
self.class.fields
|
234
|
-
end
|
235
|
-
|
236
|
-
def indexed_fields
|
237
|
-
self.class.indexed_fields
|
238
|
-
end
|
239
|
-
|
240
|
-
def [](k)
|
241
|
-
__send__(k)
|
242
|
-
end
|
243
|
-
|
244
|
-
def []=(k, v)
|
245
|
-
__send__("#{k}=", v)
|
246
|
-
end
|
247
|
-
|
248
|
-
def ==(o)
|
249
|
-
return false if (o == nil) || (o == false)
|
250
|
-
return false unless o.respond_to?(:[])
|
251
|
-
fields.all? do |fld|
|
252
|
-
if fld.rule == :repeated
|
253
|
-
Array(self[fld.name]) == Array(o[fld.name])
|
254
|
-
else
|
255
|
-
self[fld.name] == o[fld.name]
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
def inspect
|
261
|
-
set = fields.select {|fld| self[fld.name] != nil }
|
262
|
-
|
263
|
-
flds = set.map do |fld|
|
264
|
-
val = self[fld.name]
|
265
|
-
|
266
|
-
case fld.type
|
267
|
-
when Class
|
268
|
-
"#{fld.name}: #{val.inspect}"
|
269
|
-
when Module
|
270
|
-
title = name_for(fld.type, val) || "-NA-"
|
271
|
-
"#{fld.name}: #{title}(#{val.inspect})"
|
272
|
-
else
|
273
|
-
"#{fld.name}: #{val.inspect}"
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
"<#{self.class.name} #{flds.join(", ")}>"
|
278
|
-
end
|
279
|
-
|
280
|
-
def to_hash
|
281
|
-
fields.inject({}) do |h, fld|
|
282
|
-
if v = self[fld.name]
|
283
|
-
h[fld.name] = v
|
284
|
-
end
|
285
|
-
h
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
end
|
290
|
-
|
291
|
-
end
|
292
|
-
end
|