fin 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/README.rdoc +5 -5
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/lib/fin.rb +2 -5
- data/lib/fin/book.rb +2 -2
- data/lib/fin/book_manager.rb +1 -1
- data/lib/fin/changed_list.rb +1 -1
- data/lib/fin/container_list.rb +10 -1
- data/lib/fin/deal_list.rb +2 -2
- data/lib/fin/models/deal.rb +44 -50
- data/lib/fin/models/instrument.rb +39 -57
- data/lib/fin/models/model.rb +112 -16
- data/lib/fin/models/money_limit.rb +29 -58
- data/lib/fin/models/order.rb +51 -26
- data/lib/fin/models/position.rb +13 -36
- data/lib/fin/models/quote.rb +40 -0
- data/lib/fin/quote_list.rb +17 -0
- data/lib/version.rb +1 -1
- data/spec/fin/book_spec.rb +17 -17
- data/spec/fin/deal_list_spec.rb +3 -3
- data/spec/fin/models/deal_spec.rb +49 -117
- data/spec/fin/models/instrument_spec.rb +32 -34
- data/spec/fin/models/model_spec.rb +215 -75
- data/spec/fin/models/money_limit_spec.rb +48 -119
- data/spec/fin/models/order_spec.rb +29 -48
- data/spec/fin/models/position_spec.rb +34 -55
- data/spec/fin/models/quote_spec.rb +73 -0
- data/spec/fin/models/shared_examples.rb +84 -3
- data/spec/fin/order_list_spec.rb +12 -12
- data/spec/fin/shared_examples.rb +1 -1
- data/tasks/common.rake +2 -2
- data/tasks/spec.rake +1 -1
- data/tasks/version.rake +7 -7
- metadata +6 -3
- data/lib/fin/order_list.rb +0 -17
data/HISTORY
CHANGED
data/README.rdoc
CHANGED
@@ -13,8 +13,8 @@ other markets and other data feed types.
|
|
13
13
|
|
14
14
|
Domain models represent distinct individual entities that appear in market data feeds
|
15
15
|
(such as Quote, Order, Deal, Instrument, Position and whatnot). Intention is to keep
|
16
|
-
|
17
|
-
|
16
|
+
model API very similar to ActiveModel, with a goal of full ActiveModel compatibility
|
17
|
+
in the near future.
|
18
18
|
|
19
19
|
Enclosed data structures (Lists and such) are effectively containers for domain objects.
|
20
20
|
They are used to accumulate, analyse and visualize sets of domain objects, received from
|
@@ -24,9 +24,9 @@ by client and gateway components (data adapters) that deal with actual market da
|
|
24
24
|
data analysers for storage and retrieval of domain objects passing through them.
|
25
25
|
|
26
26
|
Ideally, container data structures need to be:
|
27
|
-
1
|
28
|
-
2
|
29
|
-
3
|
27
|
+
1. memory-efficient
|
28
|
+
2. thread-safe (without too much synchronization penalty)
|
29
|
+
3. iteration-safe (adding new element while iterating should not raise exception)
|
30
30
|
|
31
31
|
== INSTALL:
|
32
32
|
|
data/Rakefile
CHANGED
@@ -9,9 +9,9 @@ end
|
|
9
9
|
require 'pathname'
|
10
10
|
|
11
11
|
BASE_PATH = Pathname.new(__FILE__).dirname
|
12
|
-
LIB_PATH =
|
13
|
-
PKG_PATH =
|
14
|
-
DOC_PATH =
|
12
|
+
LIB_PATH = BASE_PATH + 'lib'
|
13
|
+
PKG_PATH = BASE_PATH + 'pkg'
|
14
|
+
DOC_PATH = BASE_PATH + 'rdoc'
|
15
15
|
|
16
16
|
$LOAD_PATH.unshift LIB_PATH.to_s
|
17
17
|
require 'version'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/lib/fin.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
1
|
require 'version'
|
2
|
-
require 'rubygems'
|
3
|
-
require 'bundler/setup'
|
4
|
-
Bundler.require(:default)
|
5
2
|
|
6
|
-
require 'fin/
|
7
|
-
require 'fin/order_list'
|
3
|
+
require 'fin/quote_list'
|
8
4
|
require 'fin/deal_list'
|
9
5
|
require 'fin/models/deal'
|
6
|
+
require 'fin/models/quote'
|
10
7
|
require 'fin/models/order'
|
11
8
|
require 'fin/models/instrument'
|
12
9
|
require 'fin/models/position'
|
data/lib/fin/book.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'fin/container_list'
|
2
2
|
|
3
3
|
module Fin
|
4
|
-
# Represents Book (
|
5
|
-
# It is used as additional index by BookedList subclass (
|
4
|
+
# Represents Book (QuoteBook, DealBook, etc...) for one security(isin)
|
5
|
+
# It is used as additional index by BookedList subclass (QuoteList, DealList)
|
6
6
|
class Book < ContainerList
|
7
7
|
|
8
8
|
attr_reader :isin_id
|
data/lib/fin/book_manager.rb
CHANGED
@@ -5,7 +5,7 @@ module Fin
|
|
5
5
|
# Adds to including List a set of @books, each related to a single security(isin).
|
6
6
|
# @books is effectively an additional index in a List, a set of containers for
|
7
7
|
# its items, grouped by item's isin_id.
|
8
|
-
# For example:
|
8
|
+
# For example: QuoteBook, DealBook
|
9
9
|
#
|
10
10
|
module BookManager
|
11
11
|
|
data/lib/fin/changed_list.rb
CHANGED
data/lib/fin/container_list.rb
CHANGED
@@ -22,12 +22,21 @@ module Fin
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def add_record rec
|
25
|
-
add? @item_type.from_record
|
25
|
+
add? @item_type.from_record rec
|
26
26
|
end
|
27
27
|
|
28
28
|
def remove_record rec, id
|
29
29
|
index = @item_type.index_for rec
|
30
30
|
remove? self[index]
|
31
31
|
end
|
32
|
+
|
33
|
+
def add_message msg
|
34
|
+
add? @item_type.from_msg msg
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove_message msg, id
|
38
|
+
item = @item_type.from_msg msg
|
39
|
+
remove? self[item.index]
|
40
|
+
end
|
32
41
|
end
|
33
42
|
end
|
data/lib/fin/deal_list.rb
CHANGED
@@ -2,8 +2,8 @@ require 'fin/models/deal'
|
|
2
2
|
require 'fin/book_manager'
|
3
3
|
|
4
4
|
module Fin
|
5
|
-
# Represents list of ALL
|
6
|
-
# Its @books is a set of
|
5
|
+
# Represents list of ALL Deals, indexed by deal_id
|
6
|
+
# Its @books is a set of DealBooks by isin_id. Each DealBook lists Deals by deal_id.
|
7
7
|
class DealList < ContainerList
|
8
8
|
|
9
9
|
include BookManager
|
data/lib/fin/models/deal.rb
CHANGED
@@ -2,74 +2,68 @@ require 'fin/models/model'
|
|
2
2
|
|
3
3
|
module Fin
|
4
4
|
# Represents a single deal (trade) for one security
|
5
|
-
# Source table: FORTS_FUTTRADE_REPL::deal � c�����
|
5
|
+
# Source table: FORTS_FUTTRADE_REPL::deal / user_deal � c�����
|
6
6
|
#
|
7
7
|
class Deal < Model
|
8
|
+
model_class_id 11
|
8
9
|
|
9
10
|
# Properties as per P2ClientGate API
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
:nosystem, # i1 1-������������ ������, 0-�������
|
19
|
-
[:repo_id, :repo, :id_repo], # i8 ����� ������ ����� ������ ����
|
20
|
-
:id_deal_multileg # i8 ����� ������ �� ������
|
11
|
+
property :isin_id => :i4, # - ���������� �������� �����. �����������
|
12
|
+
:price => :'d16.5', # - ����
|
13
|
+
:amount => :i4, # - �����, ���-�� ������ �����������
|
14
|
+
[:id_deal, :deal_id] => :i8, # - ����� ������
|
15
|
+
[:sess_id, :session_id] => :i4, # ������������� ������
|
16
|
+
:moment => :t, # ����� ���������� ������.
|
17
|
+
:pos => :i4, # ���-�� ������� �� ����������� �� ����� ����� ������.
|
18
|
+
:nosystem => :i1 # 1-������������ ������, 0-�������
|
21
19
|
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
:ext_id_sell, # i4 ������� ����� �� ������ ��������
|
26
|
-
:comment_sell, # c20 ����������� �� ������ ��������.
|
27
|
-
:trust_sell, # i1 ������� �� (�������������� ����������) �� ������ ��������
|
28
|
-
:status_sell, # i4 ������ ������ �� ������� ��������
|
29
|
-
:hedge_sell, # i1 ������� �������� ������ �� ������� ��������
|
30
|
-
:fee_sell, # d26.2 ���� �� ������ ��������
|
31
|
-
:login_sell, # c20 ����� ������������ ��������
|
32
|
-
:code_rts_sell, # c7 ��� ��� ��������
|
33
|
-
:code_buy, # c7 ��� ����������
|
34
|
-
:id_ord_buy, # i8 ����� ������ ����������.
|
35
|
-
:ext_id_buy, # i4 ������� ����� �� ������ ����������
|
36
|
-
:comment_buy, # c20 ����������� �� ������ ����������
|
37
|
-
:trust_buy, # i1 ������� �� (�������������� ����������) �� ������ ����������
|
38
|
-
:status_buy, # i4 ������ ������ �� ������� ����������
|
39
|
-
:hedge_buy, # i1 ������� �������� ������ �� ������� ����������
|
40
|
-
:fee_buy, # d26.2 ���� �� ������ ����������
|
41
|
-
:login_buy, # c20 ����� ������������ ����������
|
42
|
-
:code_rts_buy # c7 ��� ��� ����������
|
20
|
+
# Optional fields, only for repo/multileg deals:
|
21
|
+
property [:id_deal_multileg, :deal_multileg_id] => :i8, # ����� ������ �� ������
|
22
|
+
[:id_repo, :repo_id] => :i8 # ����� ������ ����� ������ ����
|
43
23
|
|
44
|
-
|
24
|
+
# Optional fields, only for OWN deals:
|
25
|
+
property :code_sell => :c7, # ��� ��������:status_sell,
|
26
|
+
:id_ord_sell => :i8, # ����� ������ ��������
|
27
|
+
:ext_id_sell => :i4, # ������� ����� �� ������ ��������
|
28
|
+
:comment_sell => :c20, # ����������� �� ������ ��������.
|
29
|
+
:trust_sell => :i1, # ������� �������������� ���������� �� ������ ��������
|
30
|
+
:status_sell => :i4, # ������ ������ �� ������� ��������
|
31
|
+
:hedge_sell => :i1, # ������� �������� ������ �� ������� ��������
|
32
|
+
:fee_sell => :'d26.2', # ���� �� ������ ��������
|
33
|
+
:login_sell => :c20, # ����� ������������ ��������
|
34
|
+
:code_rts_sell => :c7, # ��� ��� ��������
|
35
|
+
:code_buy => :c7, # ��� ����������
|
36
|
+
:id_ord_buy => :i8, # ����� ������ ����������.
|
37
|
+
:ext_id_buy => :i4, # ������� ����� �� ������ ����������
|
38
|
+
:comment_buy => :c20, # ����������� �� ������ ����������
|
39
|
+
:trust_buy => :i1, # ������� �������������� ���������� �� ������ ����������
|
40
|
+
:status_buy => :i4, # ������ ������ �� ������� ����������
|
41
|
+
:hedge_buy => :i1, # ������� �������� ������ �� ������� ����������
|
42
|
+
:fee_buy => :'d26.2', # ���� �� ������ ����������
|
43
|
+
:login_buy => :c20, # ����� ������������ ����������
|
44
|
+
:code_rts_buy => :c7 # ��� ��� ����������
|
45
45
|
|
46
|
-
|
47
|
-
new :isin_id => rec.GetValAsLong('isin_id'),
|
48
|
-
:deal_id => rec.GetValAsLong('id_deal'),
|
49
|
-
:id => rec.GetValAsString('replID').to_i,
|
50
|
-
:rev => rec.GetValAsString('replRev').to_i,
|
51
|
-
:price => rec.GetValAsString('price').to_f,
|
52
|
-
:moment => rec.GetValAsString('moment'),
|
53
|
-
:amount => rec.GetValAsString('amount').to_i
|
54
|
-
end
|
46
|
+
attr_accessor :book
|
55
47
|
|
56
48
|
def self.index_for rec
|
57
49
|
rec.GetValAsLong('id_deal')
|
58
50
|
end
|
59
51
|
|
60
52
|
def index
|
61
|
-
|
53
|
+
deal_id
|
62
54
|
end
|
63
55
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
56
|
+
def price_as_integer
|
57
|
+
if price && price.round == price
|
58
|
+
price.to_i
|
59
|
+
else
|
60
|
+
price
|
61
|
+
end
|
67
62
|
end
|
68
63
|
|
69
|
-
def
|
70
|
-
"#{moment}:#{
|
64
|
+
def to_s
|
65
|
+
"#{moment}:#{deal_id}[#{isin_id}] #{price}>#{amount}"
|
71
66
|
end
|
72
67
|
|
73
|
-
alias to_s inspect
|
74
68
|
end
|
75
69
|
end
|
@@ -5,74 +5,56 @@ module Fin
|
|
5
5
|
# Source table: FORTS_FUTINFO_REPL::fut_sess_contents
|
6
6
|
#
|
7
7
|
class Instrument < Model
|
8
|
+
model_class_id 12
|
8
9
|
|
9
10
|
# Properties as per P2ClientGate API
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
:step_price_interclr, # d16.5 ��������� ���� ���� ����. ��������
|
47
|
-
:step_price_curr # d16.5 ��������� ������������ ���� ����, ���������� � ������
|
48
|
-
|
49
|
-
def self.from_record rec
|
50
|
-
new :isin_id => rec.GetValAsLong('isin_id'),
|
51
|
-
:isin => rec.GetValAsString('isin'),
|
52
|
-
:short_isin => rec.GetValAsString('short_isin'),
|
53
|
-
:name => rec.GetValAsString('name'),
|
54
|
-
:inst_term => rec.GetValAsLong('inst_term'),
|
55
|
-
:code_vcb => rec.GetValAsString('code_vcb'),
|
56
|
-
|
57
|
-
end
|
11
|
+
property [:sess_id, :session_id] => :i4, # ����� ������.
|
12
|
+
:isin_id => :i4, # ���������� �������� ��� �����������.
|
13
|
+
:isin => :c25, # ���������� ��� �����������
|
14
|
+
:short_isin => :c25, # ��������� �����������.
|
15
|
+
:name => :c75, # ������������ �����������.
|
16
|
+
:inst_term => :i4, # �������� �� �����.
|
17
|
+
:code_vcb => :c25, # ��� ���������.
|
18
|
+
:is_limited => :i1, # ������� ������� ������� � ������.
|
19
|
+
:limit_up => :'d16.5', # ������� ����� ����.
|
20
|
+
:limit_down => :'d16.5', # ������ ����� ����.
|
21
|
+
:old_kotir => :'d16.5', # ����������������� ��������� ���� ���������� ������.
|
22
|
+
:buy_deposit => :'d16.2', # �� ����������.
|
23
|
+
:sell_deposit => :'d16.2', #�� ��������.
|
24
|
+
:roundto => :i4, # ���������� ������ ����� ������� � ����.
|
25
|
+
:min_step => :'d16.5', # ����������� ��� ����.
|
26
|
+
:step_price => :'d16.5', # ��������� ���� ����.
|
27
|
+
:d_pg => :t, # ���� ��������� ��������� �����������.
|
28
|
+
:is_spread => :i1, # ������� ��������� �������� � ����������� �����.
|
29
|
+
# 1 � ������; 0 � �� ������.
|
30
|
+
:coeff => :'d9.6', # ����������� ������������ ������.
|
31
|
+
:d_exp => :t, # ���� ���������� �����������.
|
32
|
+
:is_percent => :i1, # ������� ��������� � ���������?
|
33
|
+
# 1 - ��������� � ���������, 0 � �� � ���������
|
34
|
+
:percent_rate => :'d6.2', # ���������� ������ ��� ������� ������������
|
35
|
+
# ����� �� ���������� ���������.
|
36
|
+
:last_cl_quote => :'d16.5', # ��������� ����� ���������� ��������.
|
37
|
+
:signs => :i4, # ���� ���������.
|
38
|
+
:is_trade_evening => :i1, # ������� �������� � �������� ������.
|
39
|
+
:ticker => :i4, # ���������� �������� ��� �������� �����.
|
40
|
+
:state => :i4, # ��������� �������� �� �����������
|
41
|
+
:price_dir => :i1, # ����������� ���� �����������
|
42
|
+
:multileg_type => :i1, # ��� ������
|
43
|
+
:legs_qty => :i4, # ���������� ������������ � ������
|
44
|
+
:step_price_clr => :'d16.5', # C�������� ���� ���� ��������� ��������
|
45
|
+
:step_price_interclr => :'d16.5', # ��������� ���� ���� ����. ��������
|
46
|
+
:step_price_curr => :'d16.5' # ��������� ������������ ���� ���� � ������
|
58
47
|
|
59
48
|
def self.index_for rec
|
60
49
|
rec.GetValAsLong('isin_id')
|
61
50
|
end
|
62
51
|
|
63
52
|
def index
|
64
|
-
|
53
|
+
isin_id
|
65
54
|
end
|
66
55
|
|
67
|
-
def
|
68
|
-
val = val.to_f
|
69
|
-
@price = val.round == val ? val.to_i : val
|
70
|
-
end
|
71
|
-
|
72
|
-
def inspect
|
56
|
+
def to_s
|
73
57
|
"#{name}:#{short_isin}[#{isin}]"
|
74
58
|
end
|
75
|
-
|
76
|
-
alias to_s inspect
|
77
59
|
end
|
78
60
|
end
|
data/lib/fin/models/model.rb
CHANGED
@@ -1,39 +1,135 @@
|
|
1
1
|
module Fin
|
2
|
-
# Represents business domain model for a single item (
|
3
|
-
#
|
4
|
-
# down the road
|
2
|
+
# Represents business domain model for a single item (Quote, Deal, Instrument, etc...)
|
3
|
+
# Currently it is only used to extract common functionality from record wrappers,
|
4
|
+
# down the road the goal is to add ActiveModel compatibility
|
5
5
|
class Model
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def self.attribute_types
|
10
|
+
@attribute_types ||= superclass.attribute_types.dup rescue {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.model_class_id value = nil
|
14
|
+
if value
|
15
|
+
@model_class_id ||= value
|
16
|
+
model_classes[@model_class_id] = self
|
17
|
+
else
|
18
|
+
@model_class_id
|
14
19
|
end
|
15
20
|
end
|
16
21
|
|
17
|
-
def self.
|
18
|
-
|
22
|
+
def self.model_classes
|
23
|
+
@model_classes ||= superclass.model_classes rescue {} #shared list for all subclasses
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.property prop_hash
|
27
|
+
prop_hash.each do |arg, type|
|
19
28
|
aliases = [arg].flatten
|
20
29
|
name = aliases.shift
|
21
30
|
instance_eval do
|
22
|
-
|
31
|
+
|
32
|
+
attribute_types[name.to_s] = type.to_s
|
33
|
+
|
34
|
+
define_method(name) do
|
35
|
+
@attributes[name]
|
36
|
+
end
|
37
|
+
|
38
|
+
define_method("#{name}=") do |value|
|
39
|
+
@attributes[name] = value
|
40
|
+
end
|
41
|
+
|
23
42
|
aliases.each do |ali|
|
24
43
|
alias_method "#{ali}", name
|
25
44
|
alias_method "#{ali}=", "#{name}="
|
26
45
|
end
|
27
46
|
end
|
28
47
|
end
|
48
|
+
|
49
|
+
# Using static calls, create class method extracting attributes from raw records
|
50
|
+
attribute_extractor = attribute_types.map do |name, type|
|
51
|
+
case type
|
52
|
+
when /^[ct]/ # TODO: In future, read t AsLong and convert into DateTime
|
53
|
+
"rec.GetValAsString('#{name}')"
|
54
|
+
when /^i[14]/
|
55
|
+
"rec.GetValAsLong('#{name}')"
|
56
|
+
when /^i8/
|
57
|
+
"rec.GetValAsString('#{name}').to_i"
|
58
|
+
when /^[df]/
|
59
|
+
"rec.GetValAsString('#{name}').to_f"
|
60
|
+
else
|
61
|
+
raise "Unrecognized attribute type: #{name} => #{type}"
|
62
|
+
end
|
63
|
+
end.join(",\n")
|
64
|
+
|
65
|
+
extractor_body = "def self.extract_attributes rec
|
66
|
+
[#{attribute_extractor}]
|
67
|
+
end"
|
68
|
+
|
69
|
+
# puts "In #{self}:, #{extractor_body"
|
70
|
+
instance_eval extractor_body
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.from_record rec
|
74
|
+
new *extract_attributes(rec)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Unpacks attributes into appropriate Model subclass
|
78
|
+
def self.from_msg msg
|
79
|
+
class_id = msg.first
|
80
|
+
model_classes[class_id].new *msg[1..-1]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Extracts attributes from record into a serializable format (Array)
|
84
|
+
# Returns an Array where 1st element is a model_class_id of our Model subclass,
|
85
|
+
# and second element is a list of arguments to its initialize. Class method!
|
86
|
+
def self.to_msg rec
|
87
|
+
extract_attributes(rec).unshift(model_class_id)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Converts OBJECT attributes into a serializable format (Array)
|
91
|
+
# Returns an Array where 1st element is a model_class_id of our Model subclass,
|
92
|
+
# and second element is a list of arguments to its initialize. Instance method!
|
93
|
+
def to_msg
|
94
|
+
inject([self.class.model_class_id]) { |array, (name, _)| array << send(name) }
|
29
95
|
end
|
30
96
|
|
31
|
-
|
32
|
-
|
97
|
+
# TODO: Builder pattern, to avoid args Array creation on each initialize?
|
98
|
+
def initialize *args
|
99
|
+
@attributes = {}
|
100
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
101
|
+
each_with_index { |(name, _), i| send "#{name}=", args[i] } unless args.empty?
|
102
|
+
opts.each { |name, value| send "#{name}=", value }
|
33
103
|
end
|
34
104
|
|
105
|
+
def each
|
106
|
+
if block_given?
|
107
|
+
self.class.attribute_types.each { |name, _| yield name, send(name) }
|
108
|
+
else
|
109
|
+
self.class.attribute_types.map { |name, _| [name, send(name)].to_enum }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
alias each_property each
|
114
|
+
|
115
|
+
def inspect divider=','
|
116
|
+
map { |property, value| "#{property}=#{value}" }.join(divider)
|
117
|
+
end
|
118
|
+
|
119
|
+
# TODO: DRY principle: there should be one authoritative source for everything...
|
120
|
+
# TODO: Should such source be schema file, or Model code?
|
121
|
+
# TODO: Maybe, Model should just read from schema file at init time?
|
122
|
+
|
123
|
+
# All P2 records carry these properties
|
124
|
+
property [:replID, :repl_id] => :i8,
|
125
|
+
[:replRev, :repl_rev, :rev] => :i8,
|
126
|
+
[:replAct, :repl_act] => :i8
|
127
|
+
|
35
128
|
def index
|
36
129
|
object_id # TODO: @repl_id?
|
37
130
|
end
|
131
|
+
|
132
|
+
# Fin::Model itself has model_class_id 0
|
133
|
+
model_class_id 0
|
38
134
|
end
|
39
135
|
end
|