xbrlware-ce 1.0.4 → 1.1.0
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/Rakefile.rb +4 -4
- data/Readme.txt +6 -1
- data/ReleaseNotes.txt +22 -5
- data/doc/classes/Edgar/HTMLFeedDownloader.html +8 -8
- data/doc/classes/Edgar/RSSFeedDownloader.html +15 -15
- data/doc/classes/Xbrlware.html +22 -0
- data/doc/classes/Xbrlware/Context.html +104 -74
- data/doc/classes/Xbrlware/Context/Period.html +305 -0
- data/doc/classes/Xbrlware/Entity.html +75 -51
- data/doc/classes/Xbrlware/Identifier.html +17 -17
- data/doc/classes/Xbrlware/Instance.html +165 -137
- data/doc/classes/Xbrlware/Item.html +19 -19
- data/doc/classes/Xbrlware/Linkbase/CalculationLinkbase/Calculation.html +1 -1
- data/doc/classes/Xbrlware/Linkbase/DefinitionLinkbase/Definition.html +2 -2
- data/doc/classes/Xbrlware/Linkbase/Linkbase/Link.html +9 -3
- data/doc/classes/Xbrlware/Linkbase/Linkbase/Link/Arc.html +4 -4
- data/doc/classes/Xbrlware/Linkbase/PresentationLinkbase/Presentation.html +1 -1
- data/doc/classes/Xbrlware/Report.html +352 -0
- data/doc/classes/Xbrlware/Taxonomy.html +48 -48
- data/doc/classes/Xbrlware/TaxonomyDefintion.html +15 -15
- data/doc/classes/Xbrlware/Unit.html +6 -6
- data/doc/classes/Xbrlware/Unit/Divide.html +6 -6
- data/doc/created.rid +1 -1
- data/doc/files/Readme_txt.html +9 -1
- data/doc/files/lib/xbrlware/context_rb.html +1 -1
- data/doc/files/lib/xbrlware/date_util_rb.html +1 -1
- data/doc/files/lib/xbrlware/instance_rb.html +1 -1
- data/doc/files/lib/xbrlware/linkbase/calculation_linkbase_rb.html +1 -1
- data/doc/files/lib/xbrlware/linkbase/definition_linkbase_rb.html +1 -1
- data/doc/files/lib/xbrlware/linkbase/linkbase_rb.html +1 -1
- data/doc/files/lib/xbrlware/linkbase/presentation_linkbase_rb.html +1 -1
- data/doc/files/lib/xbrlware/meta_util_rb.html +1 -1
- data/doc/files/lib/xbrlware/report_rb.html +101 -0
- data/doc/files/lib/xbrlware/taxonomy_rb.html +1 -1
- data/doc/files/lib/xbrlware/version_rb.html +129 -0
- data/doc/fr_class_index.html +2 -0
- data/doc/fr_file_index.html +2 -0
- data/doc/fr_method_index.html +75 -62
- data/example/case_study/buy_strategy.rb +1 -1
- data/example/case_study/c_sell_strategy.rb +1 -1
- data/lib/xbrlware/context.rb +77 -34
- data/lib/xbrlware/date_util.rb +16 -6
- data/lib/xbrlware/instance.rb +35 -28
- data/lib/xbrlware/linkbase/calculation_linkbase.rb +1 -1
- data/lib/xbrlware/linkbase/definition_linkbase.rb +2 -2
- data/lib/xbrlware/linkbase/linkbase.rb +3 -2
- data/lib/xbrlware/linkbase/presentation_linkbase.rb +1 -1
- data/lib/xbrlware/meta_util.rb +5 -0
- data/lib/xbrlware/report.rb +277 -0
- data/lib/xbrlware/taxonomy.rb +13 -10
- data/lib/xbrlware/version.rb +22 -0
- data/test/lib/xbrlware/47_context_test.rb +13 -4
- data/test/lib/xbrlware/date_util_test.rb +10 -2
- data/test/lib/xbrlware/instance_test.rb +19 -0
- data/test/lib/xbrlware/meta_util_test.rb +21 -1
- metadata +10 -4
|
@@ -21,7 +21,7 @@ end
|
|
|
21
21
|
|
|
22
22
|
curr_asset, prev_asset=0, 0
|
|
23
23
|
|
|
24
|
-
if
|
|
24
|
+
if assets[0].context.period.value > assets[1].context.period.value
|
|
25
25
|
curr_asset=assets[0].value.to_f
|
|
26
26
|
prev_asset=assets[1].value.to_f
|
|
27
27
|
else
|
|
@@ -14,7 +14,7 @@ end
|
|
|
14
14
|
|
|
15
15
|
curr_netincome, prev_netincome=0, 0
|
|
16
16
|
|
|
17
|
-
if
|
|
17
|
+
if net_incomes[0].context.period.value["end_date"] > net_incomes[1].context.period.value["end_date"]
|
|
18
18
|
curr_netincome=net_incomes[0].value.to_f
|
|
19
19
|
prev_netincome=net_incomes[1].value.to_f
|
|
20
20
|
else
|
data/lib/xbrlware/context.rb
CHANGED
|
@@ -21,29 +21,66 @@ module Xbrlware
|
|
|
21
21
|
# This class represents each context in the XBRL instance file.
|
|
22
22
|
# Look at {delaing with instance page on xbrlware wiki}[http://code.google.com/p/xbrlware/wiki/InstanceTaxonomy] for more details.
|
|
23
23
|
class Context
|
|
24
|
-
attr_reader :id
|
|
24
|
+
attr_reader :id, :entity, :period, :scenario
|
|
25
25
|
PERIOD_FOREVER = -1
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
class Period
|
|
28
|
+
attr_reader :value
|
|
29
|
+
|
|
30
|
+
def initialize(value)
|
|
31
|
+
@value = value
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_s
|
|
35
|
+
@value.to_s
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def eql?(o)
|
|
39
|
+
o.is_a?(Period) && @value == o.value
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def hash
|
|
43
|
+
@value.hash
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def is_instant?
|
|
47
|
+
@value.is_a?(Date)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def is_duration?
|
|
51
|
+
@value.is_a?(Hash)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def is_forever?
|
|
55
|
+
@value.is_a?(Fixnum)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def initialize(id, entity, period, scenario=nil)
|
|
27
60
|
@id = id
|
|
28
61
|
@entity = entity
|
|
29
|
-
@period = period
|
|
62
|
+
@period = Period.new(period)
|
|
30
63
|
@scenario=scenario
|
|
31
64
|
end
|
|
32
|
-
|
|
65
|
+
|
|
66
|
+
def has_scenario?
|
|
67
|
+
(not @scenario.nil?)
|
|
68
|
+
end
|
|
69
|
+
|
|
33
70
|
def to_s
|
|
34
|
-
"Id [" + id + "], Entity { " + @entity.to_s + " }, period ["+period.to_s+"]"+ (", scenario ["+scenario+"]" unless scenario.nil?).to_s
|
|
71
|
+
"Id [" + id + "], Entity { " + @entity.to_s + " }, period ["+period.to_s+"]"+ (", scenario ["+scenario+"]" unless scenario.nil?).to_s
|
|
35
72
|
end
|
|
36
|
-
|
|
73
|
+
|
|
37
74
|
def eql?(o)
|
|
38
75
|
o.is_a?(Context) && @id == o.id
|
|
39
76
|
end
|
|
40
|
-
|
|
77
|
+
|
|
41
78
|
def hash
|
|
42
79
|
@id.hash
|
|
43
80
|
end
|
|
44
|
-
|
|
81
|
+
|
|
45
82
|
def has_explicit_dimensions?(dimensions=[])
|
|
46
|
-
return @entity.has_explicit_dimensions?(dimensions) unless @entity.nil?
|
|
83
|
+
return @entity.has_explicit_dimensions?(dimensions) unless @entity.nil?
|
|
47
84
|
false
|
|
48
85
|
end
|
|
49
86
|
|
|
@@ -54,10 +91,10 @@ module Xbrlware
|
|
|
54
91
|
end
|
|
55
92
|
|
|
56
93
|
alias_method :dimensions, :explicit_dimensions
|
|
57
|
-
|
|
94
|
+
|
|
58
95
|
def explicit_domains(dimensions=[])
|
|
59
96
|
return @entity.explicit_domains(dimensions)
|
|
60
|
-
end
|
|
97
|
+
end
|
|
61
98
|
|
|
62
99
|
alias_method :domains, :explicit_domains
|
|
63
100
|
|
|
@@ -66,37 +103,42 @@ module Xbrlware
|
|
|
66
103
|
end
|
|
67
104
|
|
|
68
105
|
alias_method :dimensions_domains, :explicit_dimensions_domains
|
|
69
|
-
|
|
106
|
+
|
|
70
107
|
end
|
|
71
|
-
|
|
108
|
+
|
|
72
109
|
class Entity
|
|
73
|
-
attr_reader :identifier
|
|
74
|
-
|
|
110
|
+
attr_reader :identifier, :segment
|
|
111
|
+
|
|
112
|
+
def initialize(identifier, segment=nil)
|
|
75
113
|
@identifier = identifier
|
|
76
114
|
@segment = segment
|
|
77
115
|
end
|
|
78
|
-
|
|
116
|
+
|
|
117
|
+
def has_segment?
|
|
118
|
+
(not @segment.nil?)
|
|
119
|
+
end
|
|
120
|
+
|
|
79
121
|
def to_s
|
|
80
122
|
"Identifier { " + @identifier.to_s + " } " + (", segment [" + segment.to_s + "]" unless segment.nil?).to_s
|
|
81
123
|
end
|
|
82
|
-
|
|
124
|
+
|
|
83
125
|
def has_explicit_dimensions?(dimensions=[])
|
|
84
126
|
dimensions_set=Set.new
|
|
85
127
|
dimensions_set.merge(dimensions)
|
|
86
128
|
unless @segment.nil? || @segment["explicitMember"].nil?
|
|
87
|
-
|
|
88
|
-
return true if dimensions.size==0
|
|
89
|
-
|
|
129
|
+
|
|
130
|
+
return true if dimensions.size==0
|
|
131
|
+
|
|
90
132
|
dim = Set.new
|
|
91
133
|
@segment["explicitMember"].each do |member|
|
|
92
134
|
dim << member["dimension"]
|
|
93
135
|
end
|
|
94
|
-
return dim.superset?(dimensions_set)
|
|
136
|
+
return dim.superset?(dimensions_set)
|
|
95
137
|
end
|
|
96
|
-
|
|
138
|
+
|
|
97
139
|
return false
|
|
98
140
|
end
|
|
99
|
-
|
|
141
|
+
|
|
100
142
|
def explicit_dimensions
|
|
101
143
|
dim = Set.new
|
|
102
144
|
unless @segment.nil? || @segment["explicitMember"].nil?
|
|
@@ -106,7 +148,7 @@ module Xbrlware
|
|
|
106
148
|
end
|
|
107
149
|
return dim.to_a
|
|
108
150
|
end
|
|
109
|
-
|
|
151
|
+
|
|
110
152
|
def explicit_domains(dimensions=[])
|
|
111
153
|
dom = Set.new
|
|
112
154
|
if has_explicit_dimensions?(dimensions)
|
|
@@ -116,33 +158,34 @@ module Xbrlware
|
|
|
116
158
|
next unless dim==member["dimension"]
|
|
117
159
|
dom << member["content"]
|
|
118
160
|
end
|
|
119
|
-
end
|
|
161
|
+
end
|
|
120
162
|
end
|
|
121
163
|
return dom.to_a
|
|
122
164
|
end
|
|
123
|
-
|
|
165
|
+
|
|
124
166
|
def explicit_dimensions_domains
|
|
125
167
|
dim_dom={}
|
|
126
168
|
if has_explicit_dimensions?
|
|
127
169
|
@segment["explicitMember"].each do |member|
|
|
128
170
|
dim_dom[member["dimension"]]=[] if dim_dom[member["dimension"]].nil?
|
|
129
171
|
dim_dom[member["dimension"]] << member["content"]
|
|
130
|
-
end
|
|
172
|
+
end
|
|
131
173
|
end
|
|
132
174
|
return dim_dom
|
|
133
175
|
end
|
|
134
|
-
|
|
176
|
+
|
|
135
177
|
end
|
|
136
|
-
|
|
137
|
-
class Identifier
|
|
138
|
-
attr_reader :value
|
|
139
|
-
|
|
178
|
+
|
|
179
|
+
class Identifier
|
|
180
|
+
attr_reader :value, :scheme
|
|
181
|
+
|
|
182
|
+
def initialize(scheme, value)
|
|
140
183
|
@scheme = scheme
|
|
141
184
|
@value = value
|
|
142
185
|
end
|
|
143
|
-
|
|
186
|
+
|
|
144
187
|
def to_s
|
|
145
|
-
"schema [" + @scheme.to_s + "], value [" + @value.to_s + "]"
|
|
188
|
+
"schema [" + @scheme.to_s + "], value [" + @value.to_s + "]"
|
|
146
189
|
end
|
|
147
190
|
end
|
|
148
191
|
end
|
data/lib/xbrlware/date_util.rb
CHANGED
|
@@ -21,15 +21,25 @@ module Xbrlware
|
|
|
21
21
|
module DateUtil # :nodoc:
|
|
22
22
|
def self.stringify_date (date)
|
|
23
23
|
return "" if date.nil?
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
begin
|
|
25
|
+
_date=Date.parse(date) if date.is_a?(String)
|
|
26
|
+
_date=date if date.is_a?(Date)
|
|
27
|
+
m=Date::ABBR_MONTHNAMES[_date.month]
|
|
28
|
+
m + " " + _date.day.to_s + ", " + _date.year.to_s
|
|
29
|
+
rescue Exception => e
|
|
30
|
+
""
|
|
31
|
+
end
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def self.months_between(date1=Date.today, date2=Date.today)
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
begin
|
|
36
|
+
date1=Date.parse(date1) if date1.is_a?(String)
|
|
37
|
+
date2=Date.parse(date2) if date2.is_a?(String)
|
|
38
|
+
(date1 > date2) ? (recent_date, past_date = date1, date2) : (recent_date, past_date = date2, date1)
|
|
39
|
+
(recent_date.year - past_date.year) * 12 + (recent_date.month - past_date.month) + 1
|
|
40
|
+
rescue Exception => e
|
|
41
|
+
0
|
|
42
|
+
end
|
|
33
43
|
end
|
|
34
44
|
end
|
|
35
45
|
end
|
data/lib/xbrlware/instance.rb
CHANGED
|
@@ -58,6 +58,7 @@ module Xbrlware
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
@taxonomy=Xbrlware::Taxonomy.new(taxonomy_filepath, self)
|
|
61
|
+
@entity_details=Hash.new("UNKNOWN")
|
|
61
62
|
end
|
|
62
63
|
|
|
63
64
|
# Returns raw content of instance file in the form of Hash
|
|
@@ -190,9 +191,9 @@ module Xbrlware
|
|
|
190
191
|
# Returns -1 if period is forever
|
|
191
192
|
def period(period_content)
|
|
192
193
|
if period_content["startDate"] && period_content["endDate"]
|
|
193
|
-
return {"start_date" => period_content["startDate"][0]["content"], "end_date" => period_content["endDate"][0]["content"]}
|
|
194
|
+
return {"start_date" => Date.parse(period_content["startDate"][0]["content"]), "end_date" => Date.parse(period_content["endDate"][0]["content"])}
|
|
194
195
|
elsif period_content["instant"]
|
|
195
|
-
return period_content["instant"][0]["content"]
|
|
196
|
+
return Date.parse(period_content["instant"][0]["content"])
|
|
196
197
|
elsif period_content["forever"]
|
|
197
198
|
return Context::PERIOD_FOREVER
|
|
198
199
|
end
|
|
@@ -279,7 +280,7 @@ module Xbrlware
|
|
|
279
280
|
all_items.each do |name, item_content|
|
|
280
281
|
_name=name.upcase
|
|
281
282
|
next if _name=="CONTEXT" || _name=="UNIT"
|
|
282
|
-
items_hash[name.upcase] = item(name)
|
|
283
|
+
items_hash[name.upcase] = item(name)
|
|
283
284
|
end
|
|
284
285
|
items_hash
|
|
285
286
|
end
|
|
@@ -348,34 +349,40 @@ module Xbrlware
|
|
|
348
349
|
@item_footnote_map
|
|
349
350
|
end
|
|
350
351
|
|
|
352
|
+
def entity_details=(value)
|
|
353
|
+
@entity_details.merge!(value) if value.is_a?(Hash)
|
|
354
|
+
end
|
|
351
355
|
|
|
352
356
|
def entity_details
|
|
353
|
-
@entity_details={}
|
|
354
357
|
if @entity_details.size==0
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
358
|
+
begin
|
|
359
|
+
# Specific to US filing
|
|
360
|
+
e_name=item("EntityRegistrantName")[0]
|
|
361
|
+
e_ci_key=item("EntityCentralIndexKey")[0]
|
|
362
|
+
e_doc_type=item("DocumentType")[0]
|
|
363
|
+
e_doc_end_type=item("DocumentPeriodEndDate")[0]
|
|
364
|
+
|
|
365
|
+
fedate=item("CurrentFiscalYearEndDate")
|
|
366
|
+
e_fiscal_end_date=fedate[0] unless fedate.nil?
|
|
367
|
+
|
|
368
|
+
shares_outstanding = item("EntityCommonStockSharesOutstanding")
|
|
369
|
+
e_common_shares_outstanding=shares_outstanding[0] unless shares_outstanding.nil?
|
|
370
|
+
|
|
371
|
+
@entity_details["name"]=e_name.value unless e_name.nil?
|
|
372
|
+
@entity_details["ci_key"]=e_ci_key.value unless e_ci_key.nil?
|
|
373
|
+
@entity_details["doc_type"]=e_doc_type.value unless e_doc_type.nil?
|
|
374
|
+
@entity_details["doc_end_date"]=e_doc_end_type.value unless e_doc_end_type.nil?
|
|
375
|
+
@entity_details["fiscal_end_date"]=e_fiscal_end_date.value unless e_fiscal_end_date.nil?
|
|
376
|
+
@entity_details["common_shares_outstanding"]=e_common_shares_outstanding.value unless e_common_shares_outstanding.nil?
|
|
377
|
+
|
|
378
|
+
file_name=File.basename(@file_name)
|
|
379
|
+
symbol=file_name.split("-")[0]
|
|
380
|
+
symbol.upcase!
|
|
381
|
+
|
|
382
|
+
@entity_details["symbol"]=symbol unless symbol.nil?
|
|
383
|
+
rescue Exception => e
|
|
384
|
+
@entity_details
|
|
385
|
+
end
|
|
379
386
|
end
|
|
380
387
|
@entity_details
|
|
381
388
|
end
|
|
@@ -116,7 +116,7 @@ module Xbrlware
|
|
|
116
116
|
attr_reader :contexts, :entity_details
|
|
117
117
|
|
|
118
118
|
def initialize(entity_details, title, role, href=nil, arcs=nil, contexts=nil)
|
|
119
|
-
super(title, role, href, arcs)
|
|
119
|
+
super("Calculation", title, role, href, arcs)
|
|
120
120
|
@contexts=contexts
|
|
121
121
|
@entity_details=entity_details
|
|
122
122
|
end
|
|
@@ -151,7 +151,7 @@ module Xbrlware
|
|
|
151
151
|
attr_reader :primary_items
|
|
152
152
|
|
|
153
153
|
def initialize(title, role, href=nil, primary_items=nil)
|
|
154
|
-
super(title, role, href, primary_items)
|
|
154
|
+
super("Definition", title, role, href, primary_items)
|
|
155
155
|
@primary_items=primary_items
|
|
156
156
|
end
|
|
157
157
|
|
|
@@ -164,7 +164,7 @@ module Xbrlware
|
|
|
164
164
|
dimension.domains.each do |domain|
|
|
165
165
|
domains << domain.href.sub("_", ":")
|
|
166
166
|
end
|
|
167
|
-
dim_dom_map[dimension.href.sub("_", ":")]=domains
|
|
167
|
+
dim_dom_map[dimension.href.sub("_", ":")]=domains if domains.size > 0
|
|
168
168
|
end
|
|
169
169
|
end
|
|
170
170
|
end unless @primary_items.nil?
|
|
@@ -95,9 +95,10 @@ module Xbrlware
|
|
|
95
95
|
|
|
96
96
|
class Link
|
|
97
97
|
|
|
98
|
-
attr_reader :title, :role, :href, :arcs
|
|
98
|
+
attr_reader :link_type, :title, :role, :href, :arcs
|
|
99
99
|
|
|
100
|
-
def initialize(title, role, href, arcs=nil)
|
|
100
|
+
def initialize(link_type, title, role, href, arcs=nil)
|
|
101
|
+
@link_type=link_type
|
|
101
102
|
@role = role
|
|
102
103
|
@href = href
|
|
103
104
|
|
|
@@ -133,7 +133,7 @@ module Xbrlware
|
|
|
133
133
|
attr_reader :contexts, :definition, :instance, :timelines, :dimensions, :entity_details
|
|
134
134
|
|
|
135
135
|
def initialize(entity_details, title, role, href=nil, contexts=nil, arcs=nil, definition=nil, instance=nil, dimensions=[])
|
|
136
|
-
super(title, role, href, arcs)
|
|
136
|
+
super("Presentation", title, role, href, arcs)
|
|
137
137
|
@entity_details=entity_details
|
|
138
138
|
@contexts=contexts
|
|
139
139
|
@definition=definition
|
data/lib/xbrlware/meta_util.rb
CHANGED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
module Xbrlware
|
|
2
|
+
|
|
3
|
+
#This class defines methods to generate HTML reports from XBRL documents.
|
|
4
|
+
class Report
|
|
5
|
+
|
|
6
|
+
PREF={}
|
|
7
|
+
|
|
8
|
+
def initialize(entity_details={}, pref={})
|
|
9
|
+
PREF.merge!(pref)
|
|
10
|
+
PREF["ITEM_FORMAT"]=lambda{|val| (BigDecimal(val)/1000000).round(4).to_s("F")} if PREF["ITEM_FORMAT"].nil?
|
|
11
|
+
PREF["ITEM_FORMAT_DESC"]=" in millions " if PREF["ITEM_FORMAT_DESC"].nil?
|
|
12
|
+
PREF["ITEM_FORMAT_EXCLUDE"] = ["EntityRegistrantName", "EntityCentralIndexKey", "DocumentType", "DocumentPeriodEndDate", "CurrentFiscalYearEndDate", "EntityCommonStockSharesOutstanding"] if PREF["ITEM_EXCLUDE"].nil?
|
|
13
|
+
@entity_details=entity_details
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@@html_template = %{
|
|
17
|
+
<html>
|
|
18
|
+
<head>
|
|
19
|
+
<% if defined? reports_map && (not reports_map.nil?) %>
|
|
20
|
+
<title>
|
|
21
|
+
<%=reports_map["entity_details"]["symbol"].to_s + " :: " + reports_map["entity_details"]["doc_type"].to_s + " :: " + DateUtil.stringify_date(reports_map["entity_details"]["doc_end_date"]) + " :: Presentation & Calculation Reports"%>
|
|
22
|
+
</title>
|
|
23
|
+
<meta name="title" content="<%=reports_map["entity_details"]["symbol"].to_s + " :: " + reports_map["entity_details"]["doc_type"].to_s + " :: " + DateUtil.stringify_date(reports_map["entity_details"]["doc_end_date"]) + " :: Presentation & Calculation Reports"%>" />
|
|
24
|
+
<meta name="description" content="<%=reports_map["entity_details"]["name"].to_s + " ( " + reports_map["entity_details"]["symbol"].to_s + " ) :: " + reports_map["entity_details"]["doc_type"].to_s + " :: " + DateUtil.stringify_date(reports_map["entity_details"]["doc_end_date"]) + " :: Presentation & Calculation Reports" %>" />
|
|
25
|
+
<link rel="image_src" href="/static/<%=reports_map["entity_details"]["ci_key"].to_s + ".png"%>" / >
|
|
26
|
+
<% end %>
|
|
27
|
+
<meta name="Author" content="xbrlware (bitstat technologies)"/>
|
|
28
|
+
<style>
|
|
29
|
+
table, td {
|
|
30
|
+
border-color: #000000;
|
|
31
|
+
border-style: solid;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
table {
|
|
35
|
+
border-width: 0 0 1px 1px;
|
|
36
|
+
border-spacing: 0;
|
|
37
|
+
border-collapse: collapse;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
tr {
|
|
41
|
+
background-color: #FFC;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.tr_white_bg {
|
|
45
|
+
background-color: #FFFFFF;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
td {
|
|
49
|
+
margin: 0;
|
|
50
|
+
padding: 4px;
|
|
51
|
+
border-width: 1px 1px 0 0;
|
|
52
|
+
|
|
53
|
+
font-family: 'Times New Roman','Times serif';
|
|
54
|
+
font-size: 10pt;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
57
|
+
</head>
|
|
58
|
+
<body>
|
|
59
|
+
<table border="1">
|
|
60
|
+
<tr class="tr_white_bg">
|
|
61
|
+
<td><b>Entity</b></td>
|
|
62
|
+
<td><b>Presentation Reports</b></td>
|
|
63
|
+
<td><b>Calculation Reports</b></td>
|
|
64
|
+
</tr>
|
|
65
|
+
<% count=0 %>
|
|
66
|
+
<% @ins_report_map.each do |ins, reports_map| %>
|
|
67
|
+
<% if count % 2 == 0%>
|
|
68
|
+
<tr>
|
|
69
|
+
<% else %>
|
|
70
|
+
<tr class="tr_white_bg">
|
|
71
|
+
<% end %>
|
|
72
|
+
<% count=count+1 %>
|
|
73
|
+
<td>
|
|
74
|
+
<%=reports_map["entity_details"]["name"]%> (<%=reports_map["entity_details"]["symbol"]%>)
|
|
75
|
+
<br><%=reports_map["entity_details"]["doc_type"] + " : " + DateUtil.stringify_date(reports_map["entity_details"]["doc_end_date"])%>
|
|
76
|
+
</td>
|
|
77
|
+
<td valign="top">
|
|
78
|
+
<%=create_report_html(reports_map["pre"])%>
|
|
79
|
+
</td>
|
|
80
|
+
<td valign="top">
|
|
81
|
+
<%=create_report_html(reports_map["cal"])%>
|
|
82
|
+
</td>
|
|
83
|
+
</tr>
|
|
84
|
+
<% end %>
|
|
85
|
+
</table>
|
|
86
|
+
</body>
|
|
87
|
+
</html>
|
|
88
|
+
} # :nodoc:
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
def create_report_html(reports) # :nodoc:
|
|
92
|
+
return "" if reports.nil?
|
|
93
|
+
html_snipet=StringIO.new
|
|
94
|
+
reports.each do |title, report_files|
|
|
95
|
+
next if report_files.size==0
|
|
96
|
+
html_snipet << title << " "
|
|
97
|
+
report_files.each do |report_file|
|
|
98
|
+
html_snipet << "<a href='" << report_file << "'>"
|
|
99
|
+
html_snipet << File.extname(report_file).sub(".", "") << "</a> | "
|
|
100
|
+
end
|
|
101
|
+
html_snipet << "</br>"
|
|
102
|
+
end
|
|
103
|
+
html_snipet.string
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
public
|
|
107
|
+
# Takes path to folder that contains xbrl documents of entities. If the folder contains xbrl documents of single entity
|
|
108
|
+
# then HTML reports are generated for that entity. If there is need to generate reports for multiple entities then
|
|
109
|
+
# 1. Create root folder
|
|
110
|
+
# 2. Create subfolder for each entity inside root folder
|
|
111
|
+
# 3. The sub folders contains xbrl documents of the entity
|
|
112
|
+
# 4. File names of xbrl documents has to be in the following convention (if files are not in the convention mentioned below, you have to use gen_for method to generate reports)
|
|
113
|
+
# calculation linkbase document must end with _cal.xml
|
|
114
|
+
# definition linkbase document must end with _def.xml
|
|
115
|
+
# presentation linkbase document must end with _pre.xml
|
|
116
|
+
# label linkbase document must end with _lab.xml
|
|
117
|
+
# taxonomy file must end with .xsd
|
|
118
|
+
# instance document must end with .xml
|
|
119
|
+
# calling "gen" with root folder, will create reports for all entities under root folder
|
|
120
|
+
# detailed reports are stored under "reports" folder of the entity. If the "reports" doesn't exist, it
|
|
121
|
+
# will be created. Consolidated report of all generated reports is stored under root folder with name "edgar_report_index.html"
|
|
122
|
+
def gen(path_to_data_folder=".", report_for="pre|cal", report_type="html|xls|xml|json", verbose_flag="q")
|
|
123
|
+
@ins_report_map={}
|
|
124
|
+
files=xbrl_files(path_to_data_folder)
|
|
125
|
+
$LOG.info " Filtering xbrl files from folder [" + path_to_data_folder + "] done"
|
|
126
|
+
files.each do |file_map|
|
|
127
|
+
begin
|
|
128
|
+
@ins_report_map[file_map["ins"]]=gen_for(file_map, report_for, report_type, verbose_flag)
|
|
129
|
+
$LOG.info "Report generation for ["+file_map["ins"]+"] completed."
|
|
130
|
+
rescue Exception => e:
|
|
131
|
+
$LOG.fatal e.to_s
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
erb = ERB.new(@@html_template)
|
|
136
|
+
index_content=erb.result(get_binding)
|
|
137
|
+
File.open("master_report_index.html", 'w') {|f| f.write(index_content) }
|
|
138
|
+
|
|
139
|
+
rescue Exception => e:
|
|
140
|
+
$LOG.fatal e.to_s
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
def get_binding
|
|
145
|
+
binding
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
def xbrl_files(folder_path)
|
|
150
|
+
files=[]
|
|
151
|
+
presentation_files=Dir[folder_path+File::Separator+"**"+File::Separator+"*pre.xml"]
|
|
152
|
+
presentation_files.each do |pre_file|
|
|
153
|
+
files << Xbrlware::file_grep(File.dirname(pre_file))
|
|
154
|
+
end
|
|
155
|
+
files
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
def reports_content (link, report_type, verbose_flag)
|
|
160
|
+
reports_content={}
|
|
161
|
+
|
|
162
|
+
reports_content["html"]=link.to_html(verbose_flag) if report_type =~ /html|HTML/
|
|
163
|
+
reports_content["xls"]=link.to_xls if report_type =~ /xls|XLS/
|
|
164
|
+
reports_content["xml"]=link.to_xml if report_type =~ /xml|XML/
|
|
165
|
+
reports_content["json"]=link.to_json if report_type =~ /json|JSON/
|
|
166
|
+
reports_content["hash"]=link.to_hash if report_type =~ /hash|HASH/
|
|
167
|
+
|
|
168
|
+
return reports_content
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
private
|
|
172
|
+
def write_reports (links, report_dir, report_type, verbose_flag)
|
|
173
|
+
reports=HashUtil::OHash.new
|
|
174
|
+
links.each do |link|
|
|
175
|
+
reports_content=reports_content(link, report_type, verbose_flag)
|
|
176
|
+
report_name=link.title.gsub(/[^a-zA-Z0-9]/, "_")
|
|
177
|
+
report_files=[]
|
|
178
|
+
reports_content.each do |rtype, rcontent|
|
|
179
|
+
next if rcontent.nil?
|
|
180
|
+
extension = "." + rtype
|
|
181
|
+
report_dir = report_dir +File::Separator unless report_dir.end_with?(File::Separator)
|
|
182
|
+
report_file = report_dir+report_name+extension
|
|
183
|
+
File.open(report_file, 'w') {|f| f.write(rcontent) }
|
|
184
|
+
report_files << report_file
|
|
185
|
+
end
|
|
186
|
+
reports[link.title] = report_files
|
|
187
|
+
end
|
|
188
|
+
return reports
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
public
|
|
192
|
+
# Generates HTML reports from given Hash that contains files for instance, taxonomy, calculation, presentation, label, definition.
|
|
193
|
+
# Example of populating hash,
|
|
194
|
+
# files={}
|
|
195
|
+
# files["ins"] = "<instnace_file_path>"
|
|
196
|
+
# files["tax"] = "<taxonomy_file_path>"
|
|
197
|
+
# files["cal"] = "<calculation_linkbase_file_path>"
|
|
198
|
+
# files["pre"] = "<presentation_linkbase_file_path>"
|
|
199
|
+
# files["lab"] = "<label_linkbase_file_path>"
|
|
200
|
+
# files["def"] = "<definition_linkbase_file_path>"
|
|
201
|
+
# Generated HTML reports will be stored under "reports" folder of current dir. If the "reports" doesn't exist, it
|
|
202
|
+
# will be created. If "cal" is passed as null, calculation linkbase path from taxonomy will be used. Same for other
|
|
203
|
+
# linkbases too (ie, "pre", "lab" and "def".)
|
|
204
|
+
def gen_for (file_map, report_for="pre|cal", report_type="html|xls|xml|json", verbose_flag="q", report_dir=nil, meta_gen=true)
|
|
205
|
+
ins_file=file_map["ins"]
|
|
206
|
+
tax_file=file_map["tax"]
|
|
207
|
+
cal_file=file_map["cal"]
|
|
208
|
+
pre_file=file_map["pre"]
|
|
209
|
+
lab_file=file_map["lab"]
|
|
210
|
+
def_file=file_map["def"]
|
|
211
|
+
|
|
212
|
+
reports_map={}
|
|
213
|
+
|
|
214
|
+
instance=nil
|
|
215
|
+
m=Benchmark.measure do
|
|
216
|
+
instance = Instance.new(ins_file, tax_file)
|
|
217
|
+
taxonomy=instance.taxonomy
|
|
218
|
+
taxonomy.init_all_lb(cal_file, pre_file, lab_file, def_file)
|
|
219
|
+
end
|
|
220
|
+
bm(" Initializing xbrl took", m)
|
|
221
|
+
|
|
222
|
+
instance.entity_details=@entity_details
|
|
223
|
+
reports_map["entity_details"]=instance.entity_details
|
|
224
|
+
reports_map["instance"]=instance
|
|
225
|
+
|
|
226
|
+
report_dir = (File.expand_path(File.dirname(ins_file)) + File::Separator + "report" + File::Separator) if report_dir.nil?
|
|
227
|
+
File.makedirs(report_dir) unless File.directory?(report_dir)
|
|
228
|
+
|
|
229
|
+
if report_for =~ /pre/ && (not instance.taxonomy.prelb.nil?)
|
|
230
|
+
links=instance.taxonomy.prelb.presentation
|
|
231
|
+
pre_dir = report_dir + "pre"
|
|
232
|
+
File.makedirs(pre_dir) unless File.directory?(pre_dir)
|
|
233
|
+
reports_map["pre"]=write_reports(links, pre_dir, report_type, verbose_flag)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
if report_for =~ /cal/ && (not instance.taxonomy.callb.nil?)
|
|
237
|
+
links=instance.taxonomy.callb.calculation
|
|
238
|
+
cal_dir = report_dir + "cal"
|
|
239
|
+
File.makedirs(cal_dir) unless File.directory?(cal_dir)
|
|
240
|
+
reports_map["cal"]=write_reports(links, cal_dir, report_type, verbose_flag)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
_tmp = @ins_report_map
|
|
244
|
+
|
|
245
|
+
erb = ERB.new(@@html_template)
|
|
246
|
+
index_content=erb.result(lambda do
|
|
247
|
+
@ins_report_map={}
|
|
248
|
+
@ins_report_map[file_map["ins"]]=reports_map
|
|
249
|
+
lambda {}
|
|
250
|
+
end.call)
|
|
251
|
+
|
|
252
|
+
@ins_report_map = _tmp
|
|
253
|
+
|
|
254
|
+
# str_ci_key=reports_map["entity_details"]["ci_key"]
|
|
255
|
+
# str_doc_end_date=reports_map["entity_details"]["doc_end_date"]
|
|
256
|
+
# str_doc_end_date="" if str_doc_end_date.nil?
|
|
257
|
+
# str_doc_end_date.gsub!("-", "")
|
|
258
|
+
# report_index_file = report_dir + str_ci_key+"_"+str_doc_end_date+"_report.html"
|
|
259
|
+
|
|
260
|
+
report_index_file = report_dir + "report_index.html"
|
|
261
|
+
File.open( report_index_file, 'w') {|f| f.write(index_content) }
|
|
262
|
+
|
|
263
|
+
reports_map["report_index_file"]=report_index_file
|
|
264
|
+
|
|
265
|
+
if meta_gen
|
|
266
|
+
meta_file_name = report_dir + "meta.json"
|
|
267
|
+
meta_gen_content = reports_map.reject {|k, v| k=="instance"}.to_json.to_s
|
|
268
|
+
File.open( meta_file_name, 'w') {|f| f.write(meta_gen_content) }
|
|
269
|
+
reports_map["report_meta_file"]=meta_file_name
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
reports_map
|
|
273
|
+
rescue Exception => e
|
|
274
|
+
raise " Report generation failed for instance " + ins_file + "\n #{e.to_s + "\n" + e.backtrace.join("\n ")}"
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|