fios 0.1.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5ff8ffbda61ee750118e319d3110463fe4576d9a90dc012d63e3ff49b5c2087
4
- data.tar.gz: 381c885fb7ce89220177ccb6ef939589c1ee92f47c0472dcf8f3e3799e7cba31
3
+ metadata.gz: c65af31bd0d116984a3feb0410ce53348171b425bf5e0d07dd45f00a49a8bf5b
4
+ data.tar.gz: b3b3292ba5c877af0bdf3d39258a7d5c2c2f177efe5e6a657ef1ee6c72dc44d8
5
5
  SHA512:
6
- metadata.gz: a26e8780e628d7d60db56a6a567d463daba8362d7060de4ad6c313032801a184b06034aaebc7e75fef11c9f58f203128939aa4f286f295f51115734fac9a3c82
7
- data.tar.gz: 382d2090dd248d4c690ec8d7529c37af7d4cf70c66e6ebc12a5aac4c246143bbd5dc171724bf7f7bdaf2c2ce9b6dbf820814bb0f917ceedd15a351e9499f2af3
6
+ metadata.gz: 90059e0ae8e22cb45bc602c267381501c7786d7ce77520c2ea3faf639c9d496efea1f7ef673f34cfb3b55a656ba730171a2bd8d09258af153347e4ecb62f81de
7
+ data.tar.gz: 6dd0c0e6aa80bcd9baec5b1ae987ded80477d4aa9dcb654dfcd04c56a74fad68adfb5f9d0dc92953f881ac8952260d9bf322defa3bd3a2fc060d85dac61f448d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fios (0.1.0)
4
+ fios (1.0.1)
5
5
  rails (>= 6.1)
6
6
 
7
7
  GEM
data/fios.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Mark Harbison"]
9
9
  spec.email = ["mark@tyne-solutions.com"]
10
10
 
11
- spec.summary = "Fios."
12
- spec.description = "Fios."
11
+ spec.summary = "A data analytics framework for building charts, dashboards, and reports in Ruby."
12
+ spec.description = "A data analytics framework for building charts, dashboards, and reports in Ruby."
13
13
  spec.homepage = "https://github.com/CodeTectonics/fios"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = ">= 3.2.0"
@@ -0,0 +1,106 @@
1
+ module Fios
2
+ module Adapters
3
+ module ActiveRecord
4
+ class ChartQuery
5
+ def self.add_select_clause(query, chart_config)
6
+ fields = []
7
+ fields << chart_config['x_axis']['attr']
8
+
9
+ chart_config['y_axes'].each do |column|
10
+ aggregate = aggregated_attr(column['attr'], column['aggregation'])
11
+ fields << "#{aggregate[0]} AS '#{aggregate[1]}'"
12
+ end
13
+
14
+ query.select(fields)
15
+ end
16
+
17
+ def self.aggregated_attr(attr, aggregation)
18
+ case aggregation
19
+ when 'count'
20
+ ["COUNT(#{attr})", "num_#{attr}"]
21
+ when 'count_distinct'
22
+ ["COUNT(DISTINCT #{attr})", "num_uniq_#{attr}"]
23
+ when 'average'
24
+ ["AVG(#{attr})", "avg_#{attr}"]
25
+ when 'min'
26
+ ["MIN(#{attr})", "min_#{attr}"]
27
+ when 'max'
28
+ ["MAX(#{attr})", "max_#{attr}"]
29
+ when 'sum'
30
+ ["SUM(#{attr})", "sum_#{attr}"]
31
+ else
32
+ attr
33
+ end
34
+ end
35
+
36
+ def self.add_where_clause(query, chart_config)
37
+ return query if chart_config['filters'].blank?
38
+
39
+ chart_config['filters'].each do |filter|
40
+ field = filter['attr']
41
+ operator = filter['operator']
42
+ value = filter['value']
43
+
44
+ case operator
45
+ when '='
46
+ query = query.where(field => value)
47
+ when '!='
48
+ query = query.where.not(field => value)
49
+ when '>'
50
+ query = query.where("#{field} > ?", value)
51
+ when '>='
52
+ query = query.where("#{field} >= ?", value)
53
+ when '<'
54
+ query = query.where("#{field} < ?", value)
55
+ when '<='
56
+ query = query.where("#{field} <= ?", value)
57
+ when 'contains'
58
+ query = query.where("#{field} LIKE ?", "%#{value}%")
59
+ when 'starts_with'
60
+ query = query.where("#{field} LIKE ?", "#{value}%")
61
+ when 'ends_with'
62
+ query = query.where("#{field} LIKE ?", "%#{value}")
63
+ when 'one_of'
64
+ query = query.where("#{field} IN (?)", value)
65
+ when 'not_one_of'
66
+ query = query.where.not("#{field} IN (?)", value)
67
+ end
68
+ end
69
+
70
+ query
71
+ end
72
+
73
+ def self.add_group_clause(query, chart_config)
74
+ group_field = chart_config['x_axis']['attr']
75
+ query.group(group_field)
76
+ end
77
+
78
+ def self.parse_series_data(data, chart_config)
79
+ return [] if data.empty?
80
+
81
+ attrs = data[0].attribute_names
82
+ attrs.delete(chart_config['x_axis']['attr'])
83
+
84
+ attrs.map do |attr|
85
+ y_axis = chart_config['y_axes'].find do |col|
86
+ attr == aggregated_attr(col['attr'], col['aggregation'])[1]
87
+ end
88
+
89
+ { name: y_axis['label'], data: data.pluck(attr) }
90
+ end
91
+ end
92
+
93
+ def self.parse_category_data(data, chart_config, data_source)
94
+ x_axis_attr = chart_config['x_axis']['attr']
95
+
96
+ translatable = data_source.translated_columns.include?(x_axis_attr.to_sym)
97
+ data.map do |row|
98
+ return row[x_axis_attr] unless translatable
99
+
100
+ I18n.t(row[x_axis_attr], default: row[x_axis_attr])
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,88 @@
1
+ module Fios
2
+ module Adapters
3
+ module ActiveRecord
4
+ class ReportQuery
5
+ def self.add_select_clause(query, data_source, report_config)
6
+ fields = []
7
+ report_config['columns'].each do |column|
8
+ next unless column['selected']
9
+
10
+ if report_config['aggregated']
11
+ fields << column['name'] if column['group_by']
12
+ fields << "COUNT(#{column['name']}) AS 'num_#{column['name']}'" if column['count']
13
+ if column['count_distinct']
14
+ fields << "COUNT(DISTINCT #{column['name']}) AS 'num_uniq_#{column['name']}'"
15
+ end
16
+ if column['average']
17
+ if column['type'].in?(%w[date datetime])
18
+ fields << "FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(#{column['name']}))) AS 'avg_#{column['name']}'"
19
+ else
20
+ fields << "AVG(#{column['name']}) AS 'avg_#{column['name']}'"
21
+ end
22
+ end
23
+ fields << "MIN(#{column['name']}) AS 'min_#{column['name']}'" if column['min']
24
+ fields << "MAX(#{column['name']}) AS 'max_#{column['name']}'" if column['max']
25
+ fields << "SUM(#{column['name']}) AS 'sum_#{column['name']}'" if column['sum']
26
+ else
27
+ fields << column['name']
28
+ end
29
+ end
30
+
31
+ fields = data_source.column_names if fields.empty?
32
+
33
+ query.select(fields)
34
+ end
35
+
36
+ def self.add_where_clause(query, report_config)
37
+ return query if report_config['filters'].blank?
38
+
39
+ report_config['filters'].each do |filter|
40
+ field = filter['name']
41
+ operator = filter['operator']
42
+ value = filter['value']
43
+
44
+ case operator
45
+ when '='
46
+ query = query.where(field => value)
47
+ when '!='
48
+ query = query.where.not(field => value)
49
+ when '>'
50
+ query = query.where("#{field} > ?", value)
51
+ when '>='
52
+ query = query.where("#{field} >= ?", value)
53
+ when '<'
54
+ query = query.where("#{field} < ?", value)
55
+ when '<='
56
+ query = query.where("#{field} <= ?", value)
57
+ when 'contains'
58
+ query = query.where("#{field} LIKE ?", "%#{value}%")
59
+ when 'starts_with'
60
+ query = query.where("#{field} LIKE ?", "#{value}%")
61
+ when 'ends_with'
62
+ query = query.where("#{field} LIKE ?", "%#{value}")
63
+ when 'one_of'
64
+ query = query.where("#{field} IN (?)", value)
65
+ when 'not_one_of'
66
+ query = query.where.not("#{field} IN (?)", value)
67
+ end
68
+ end
69
+
70
+ query
71
+ end
72
+
73
+ def self.add_group_clause(query, report_config)
74
+ return query unless report_config['aggregated']
75
+
76
+ group_fields = []
77
+ report_config['columns'].each do |column|
78
+ next unless column['selected'] && column['group_by']
79
+
80
+ group_fields << column['name']
81
+ end
82
+
83
+ query.group(group_fields)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -7,15 +7,32 @@ module Fios
7
7
  :active_record
8
8
  end
9
9
 
10
- def initialize(dataset)
11
- @dataset = dataset
12
- @definition = Fios::Definitions::Registry.fetch(dataset.slug)
10
+ def self.fetch_chart_data(data_source, chart)
11
+ chart_config = chart.configuration
12
+
13
+ query = data_source.all
14
+ query = Fios::Adapters::ActiveRecord::ChartQuery.add_select_clause(query, chart_config)
15
+ query = Fios::Adapters::ActiveRecord::ChartQuery.add_where_clause(query, chart_config)
16
+ query = Fios::Adapters::ActiveRecord::ChartQuery.add_group_clause(query, chart_config)
17
+ data = query.to_a
18
+
19
+ {
20
+ series: Fios::Adapters::ActiveRecord::ChartQuery.parse_series_data(data, chart_config),
21
+ categories: Fios::Adapters::ActiveRecord::ChartQuery.parse_category_data(data, chart_config, data_source),
22
+ meta: {
23
+ title: chart.name,
24
+ chart_type: chart_config['chart_type']
25
+ }
26
+ }
13
27
  end
14
28
 
15
- # TODO
16
- def fetch(filters:, limit:)
17
- view = @definition.source
18
- # build SQL using filters + metadata
29
+ def self.fetch_report_data(data_source, report)
30
+ report_config = report.configuration
31
+
32
+ query = data_source.all
33
+ query = Fios::Adapters::ActiveRecord::ReportQuery.add_select_clause(query, data_source, report_config)
34
+ query = Fios::Adapters::ActiveRecord::ReportQuery.add_where_clause(query, report_config)
35
+ Fios::Adapters::ActiveRecord::ReportQuery.add_group_clause(query, report_config)
19
36
  end
20
37
  end
21
38
  end
@@ -3,16 +3,18 @@ module Fios
3
3
  module Base
4
4
  extend ActiveSupport::Concern
5
5
 
6
- attr_accessor :dataset, :definition
7
-
8
6
  class_methods do
9
7
  def adapter_key
10
8
  raise NotImplementedError
11
9
  end
12
- end
13
10
 
14
- def fetch(filters:, limit:)
15
- raise NotImplementedError
11
+ def fetch_chart_data(data_source, chart)
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def fetch_report_data(data_source, report)
16
+ raise NotImplementedError
17
+ end
16
18
  end
17
19
  end
18
20
  end
@@ -2,31 +2,28 @@ module Fios
2
2
  module Builders
3
3
  class ChartBuilder
4
4
  def self.build(chart)
5
+ data = fetch_data(chart)
6
+ parse_query_results(data)
7
+ end
8
+
9
+ def self.fetch_data(chart)
5
10
  chart_config = chart.configuration || {}
6
11
  dataset = Dataset.find(chart_config['dataset_id'])
7
- dataset_class = Fios::Services::DatasetFetcher.fetch(dataset)
8
-
9
- query = dataset_class.all
10
- query = add_select_clause(query, chart_config)
11
- query = add_where_clause(query, chart_config)
12
- query = add_group_clause(query, chart_config)
13
- parse_query_results(query, chart)
12
+ Fios::Services::DatasetFetcher.fetch_chart_data(dataset, chart)
14
13
  end
15
14
 
16
- def self.parse_query_results(query, chart)
17
- data = query.to_a
18
-
15
+ def self.parse_query_results(data)
19
16
  {
20
17
  'chart': {
21
- 'type': chart.configuration['chart_type']
18
+ 'type': data[:meta][:chart_type]
22
19
  },
23
20
 
24
21
  'title': {
25
- 'text': chart.name
22
+ 'text': data[:meta][:title]
26
23
  },
27
24
 
28
25
  'xAxis': {
29
- 'categories': parse_category_data(data, chart.configuration)
26
+ 'categories': data[:categories]
30
27
  },
31
28
 
32
29
  'yAxis': {
@@ -35,116 +32,14 @@ module Fios
35
32
  }
36
33
  },
37
34
 
38
- 'series': parse_series_data(data, chart.configuration)
35
+ 'series': data[:series]
39
36
  }
40
37
  end
41
38
 
42
- def self.parse_category_data(data, chart_config)
43
- x_axis_attr = chart_config['x_axis']['attr']
44
-
45
- dataset = Dataset.find(chart_config['dataset_id'])
46
- dataset_class = Fios::Services::DatasetFetcher.fetch(dataset)
47
-
48
- translatable = dataset_class.translated_columns.include?(x_axis_attr.to_sym)
49
- data.map do |row|
50
- return row[x_axis_attr] unless translatable
51
-
52
- I18n.t(row[x_axis_attr], default: row[x_axis_attr])
53
- end
54
- end
55
-
56
- def self.parse_series_data(data, chart_config)
57
- return [] if data.empty?
58
-
59
- attrs = data[0].attribute_names
60
- attrs.delete(chart_config['x_axis']['attr'])
61
-
62
- attrs.map do |attr|
63
- y_axis = chart_config['y_axes'].find do |col|
64
- attr == aggregated_attr(col['attr'], col['aggregation'])[1]
65
- end
66
-
67
- { name: y_axis['label'], data: data.pluck(attr) }
68
- end
69
- end
70
-
71
- def self.add_select_clause(query, chart_config)
72
- fields = []
73
- fields << chart_config['x_axis']['attr']
74
-
75
- chart_config['y_axes'].each do |column|
76
- aggregate = aggregated_attr(column['attr'], column['aggregation'])
77
- fields << "#{aggregate[0]} AS '#{aggregate[1]}'"
78
- end
79
-
80
- query.select(fields)
81
- end
82
-
83
- def self.aggregated_attr(attr, aggregation)
84
- case aggregation
85
- when 'count'
86
- ["COUNT(#{attr})", "num_#{attr}"]
87
- when 'count_distinct'
88
- ["COUNT(DISTINCT #{attr})", "num_uniq_#{attr}"]
89
- when 'average'
90
- ["AVG(#{attr})", "avg_#{attr}"]
91
- when 'min'
92
- ["MIN(#{attr})", "min_#{attr}"]
93
- when 'max'
94
- ["MAX(#{attr})", "max_#{attr}"]
95
- when 'sum'
96
- ["SUM(#{attr})", "sum_#{attr}"]
97
- else
98
- attr
99
- end
100
- end
101
-
102
- def self.add_where_clause(query, chart_config)
103
- return query if chart_config['filters'].blank?
104
-
105
- chart_config['filters'].each do |filter|
106
- field = filter['attr']
107
- operator = filter['operator']
108
- value = filter['value']
109
-
110
- case operator
111
- when '='
112
- query = query.where(field => value)
113
- when '!='
114
- query = query.where.not(field => value)
115
- when '>'
116
- query = query.where("#{field} > ?", value)
117
- when '>='
118
- query = query.where("#{field} >= ?", value)
119
- when '<'
120
- query = query.where("#{field} < ?", value)
121
- when '<='
122
- query = query.where("#{field} <= ?", value)
123
- when 'contains'
124
- query = query.where("#{field} LIKE ?", "%#{value}%")
125
- when 'starts_with'
126
- query = query.where("#{field} LIKE ?", "#{value}%")
127
- when 'ends_with'
128
- query = query.where("#{field} LIKE ?", "%#{value}")
129
- when 'one_of'
130
- query = query.where("#{field} IN (?)", value)
131
- when 'not_one_of'
132
- query = query.where.not("#{field} IN (?)", value)
133
- end
134
- end
135
-
136
- query
137
- end
138
-
139
- def self.add_group_clause(query, chart_config)
140
- group_field = chart_config['x_axis']['attr']
141
- query.group(group_field)
142
- end
143
-
144
39
  def self.build_csv(chart)
145
40
  {
146
41
  headers: csv_headers(chart),
147
- rows: build(chart)
42
+ rows: fetch_data(chart)
148
43
  }
149
44
  end
150
45
 
@@ -1,111 +1,28 @@
1
1
  module Fios
2
2
  module Builders
3
3
  class ReportBuilder
4
- def self.build(dynamic_report)
5
- report_config = dynamic_report.configuration || {}
6
-
7
- dataset = Dataset.find(report_config['dataset_id'])
8
- dataset_class = Fios::Services::DatasetFetcher.fetch(dataset)
9
-
10
- query = dataset_class.all
11
- query = add_select_clause(query, dataset_class, report_config)
12
- query = add_where_clause(query, report_config)
13
- add_group_clause(query, report_config)
14
- end
15
-
16
- def self.add_select_clause(query, dataset_class, report_config)
17
- fields = []
18
- report_config['columns'].each do |column|
19
- next unless column['selected']
20
-
21
- if report_config['aggregated']
22
- fields << column['name'] if column['group_by']
23
- fields << "COUNT(#{column['name']}) AS 'num_#{column['name']}'" if column['count']
24
- if column['count_distinct']
25
- fields << "COUNT(DISTINCT #{column['name']}) AS 'num_uniq_#{column['name']}'"
26
- end
27
- if column['average']
28
- if column['type'].in?(%w[date datetime])
29
- fields << "FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(#{column['name']}))) AS 'avg_#{column['name']}'"
30
- else
31
- fields << "AVG(#{column['name']}) AS 'avg_#{column['name']}'"
32
- end
33
- end
34
- fields << "MIN(#{column['name']}) AS 'min_#{column['name']}'" if column['min']
35
- fields << "MAX(#{column['name']}) AS 'max_#{column['name']}'" if column['max']
36
- fields << "SUM(#{column['name']}) AS 'sum_#{column['name']}'" if column['sum']
37
- else
38
- fields << column['name']
39
- end
40
- end
41
-
42
- fields = dataset_class.column_names if fields.empty?
43
-
44
- query.select(fields)
4
+ def self.build(report)
5
+ fetch_data(report)
45
6
  end
46
7
 
47
- def self.add_where_clause(query, report_config)
48
- return query if report_config['filters'].blank?
49
-
50
- report_config['filters'].each do |filter|
51
- field = filter['name']
52
- operator = filter['operator']
53
- value = filter['value']
54
-
55
- case operator
56
- when '='
57
- query = query.where(field => value)
58
- when '!='
59
- query = query.where.not(field => value)
60
- when '>'
61
- query = query.where("#{field} > ?", value)
62
- when '>='
63
- query = query.where("#{field} >= ?", value)
64
- when '<'
65
- query = query.where("#{field} < ?", value)
66
- when '<='
67
- query = query.where("#{field} <= ?", value)
68
- when 'contains'
69
- query = query.where("#{field} LIKE ?", "%#{value}%")
70
- when 'starts_with'
71
- query = query.where("#{field} LIKE ?", "#{value}%")
72
- when 'ends_with'
73
- query = query.where("#{field} LIKE ?", "%#{value}")
74
- when 'one_of'
75
- query = query.where("#{field} IN (?)", value)
76
- when 'not_one_of'
77
- query = query.where.not("#{field} IN (?)", value)
78
- end
79
- end
80
-
81
- query
82
- end
83
-
84
- def self.add_group_clause(query, report_config)
85
- return query unless report_config['aggregated']
86
-
87
- group_fields = []
88
- report_config['columns'].each do |column|
89
- next unless column['selected'] && column['group_by']
90
-
91
- group_fields << column['name']
92
- end
93
-
94
- query.group(group_fields)
8
+ def self.fetch_data(report)
9
+ report_config = report.configuration || {}
10
+ dataset = Dataset.find(report_config['dataset_id'])
11
+ Fios::Services::DatasetFetcher.fetch_report_data(dataset, report)
95
12
  end
96
13
 
97
- def self.build_csv(dynamic_report)
14
+ def self.build_csv(report)
98
15
  {
99
- headers: csv_headers(dynamic_report),
100
- rows: build(dynamic_report)
16
+ headers: csv_headers(report),
17
+ rows: fetch_data(report)
101
18
  }
102
19
  end
103
20
 
104
- def self.csv_headers(dynamic_report)
105
- report_config = dynamic_report.configuration || {}
21
+ def self.csv_headers(report)
22
+ report_config = report.configuration || {}
106
23
 
107
24
  dataset = Dataset.find(report_config['dataset_id'])
108
- dataset_class = Fios::Services::DatasetFetcher.fetch(dataset)
25
+ dataset_class = Fios::Services::DatasetFetcher.fetch_report_data(dataset, report)
109
26
 
110
27
  return dataset_class.column_names if report_config['columns'].blank?
111
28
 
@@ -1,11 +1,16 @@
1
1
  module Fios
2
2
  module Services
3
3
  class DatasetFetcher
4
- def self.fetch(dataset)
5
- adapter_klass = Fios::Adapters::Registry.fetch(dataset.adapter)
6
- adapter = adapter_klass.new(dataset)
7
- adapter.definition
8
- #adapter.fetch()
4
+ def self.fetch_chart_data(dataset, chart)
5
+ adapter = Fios::Adapters::Registry.fetch(dataset.adapter)
6
+ data_source = Fios::Definitions::Registry.fetch(dataset.slug)
7
+ data = adapter.fetch_chart_data(data_source, chart)
8
+ end
9
+
10
+ def self.fetch_report_data(dataset, report)
11
+ adapter = Fios::Adapters::Registry.fetch(dataset.adapter)
12
+ data_source = Fios::Definitions::Registry.fetch(dataset.slug)
13
+ data = adapter.fetch_report_data(data_source, report)
9
14
  end
10
15
  end
11
16
  end
data/lib/fios/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fios
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.1"
5
5
  end
data/lib/fios.rb CHANGED
@@ -5,6 +5,8 @@ require "active_support/concern"
5
5
  require "rails"
6
6
 
7
7
  require_relative "fios/adapters/base"
8
+ require_relative "fios/adapters/active_record/chart_query"
9
+ require_relative "fios/adapters/active_record/report_query"
8
10
  require_relative "fios/adapters/active_record_adapter"
9
11
  require_relative "fios/adapters/registry"
10
12
  require_relative "fios/builders/chart_builder"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fios
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Harbison
@@ -24,7 +24,8 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '6.1'
27
- description: Fios.
27
+ description: A data analytics framework for building charts, dashboards, and reports
28
+ in Ruby.
28
29
  email:
29
30
  - mark@tyne-solutions.com
30
31
  executables: []
@@ -45,6 +46,8 @@ files:
45
46
  - bin/setup
46
47
  - fios.gemspec
47
48
  - lib/fios.rb
49
+ - lib/fios/adapters/active_record/chart_query.rb
50
+ - lib/fios/adapters/active_record/report_query.rb
48
51
  - lib/fios/adapters/active_record_adapter.rb
49
52
  - lib/fios/adapters/base.rb
50
53
  - lib/fios/adapters/registry.rb
@@ -84,7 +87,8 @@ requirements: []
84
87
  rubygems_version: 3.4.19
85
88
  signing_key:
86
89
  specification_version: 4
87
- summary: Fios.
90
+ summary: A data analytics framework for building charts, dashboards, and reports in
91
+ Ruby.
88
92
  test_files:
89
93
  - spec/fios_spec.rb
90
94
  - spec/spec_helper.rb