fin 0.1.0 → 0.1.2
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/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
|