report_generator 1.0.0.beta1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ab28fc424c43db604151cd53025498f9c51d61be
4
+ data.tar.gz: 19a761e6dfbe01353bee0f1e012988cb7e225b23
5
+ SHA512:
6
+ metadata.gz: 7527c29a2e1cc669c3a90e19f4bd34a8a9b1910aed795f2df1e1a0bc6cd36f523d47cba4606c4de06c3ed9f840d93805d0a1e1cd286f9c9a6aa2c3c07db15e1b
7
+ data.tar.gz: 6f79bcbb9ee6182a8f7025bc5d8ffaa9ca583d8afdda5bcc3c65789504fc34d2681ca7f018c5756044771ceb37c642da4e6b48853760a62a2ade9b06e1ee5ea9
data/.gitignore ADDED
@@ -0,0 +1,37 @@
1
+ *.rbc
2
+ capybara-*.html
3
+ .rspec
4
+ /log
5
+ /tmp
6
+ /db/*.sqlite3
7
+ /db/*.sqlite3-journal
8
+ /public/system
9
+ /coverage/
10
+ /spec/tmp
11
+ **.orig
12
+ rerun.txt
13
+ pickle-email-*.html
14
+
15
+ # TODO Comment out these rules if you are OK with secrets being uploaded to the repo
16
+ config/initializers/secret_token.rb
17
+ config/secrets.yml
18
+
19
+ ## Environment normalization:
20
+ /.bundle
21
+ /vendor/bundle
22
+
23
+ # these should all be checked in to normalize the environment:
24
+ # Gemfile.lock, .ruby-version, .ruby-gemset
25
+
26
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
27
+ .rvmrc
28
+ .ruby-version
29
+ .ruby-gemset
30
+
31
+ # if using bower-rails ignore default bower_components path bower.json files
32
+ /vendor/assets/bower_components
33
+ *.bowerrc
34
+ bower.json
35
+
36
+ # Ignore pow environment settings
37
+ .powenv
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Evan Chiu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # report_generator [![Gem Version](https://badge.fury.io/rb/report_generator.png)](http://badge.fury.io/rb/report_generator)
2
+
3
+ A simple Ruby Internal DSL for creating Count Report which save data from MySQL to MySQL.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this to your Gemfile:
9
+
10
+ ```ruby
11
+ gem "report_generator"
12
+ ```
13
+
14
+ and run `bundle install`.
@@ -0,0 +1,11 @@
1
+ module ReportGenerator
2
+ module Definers
3
+ class ReportDefiner
4
+ def report name, &block
5
+ report_factory = ReportGenerator::Factories::ReportFactory.new
6
+ report_factory.instance_eval(&block) if block_given?
7
+ ReportGenerator.report_factories[name] = report_factory
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module ReportGenerator
2
+ module Definers
3
+ class SectionDefiner
4
+ def section name, &block
5
+ section_factory = ReportGenerator::Factories::SectionFactory.new
6
+ section_factory.instance_eval(&block) if block_given?
7
+ ReportGenerator.section_factories[name] = section_factory
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module ReportGenerator
2
+ module Factories
3
+ class AttrsFactory
4
+ attr_reader :attributes
5
+
6
+ def initialize
7
+ @attributes = {}
8
+ end
9
+
10
+ def method_missing(name, *args, &block)
11
+ @attributes[name] = args[0]
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module ReportGenerator
2
+ module Factories
3
+ class ReportFactory
4
+ attr_reader :attributes
5
+
6
+ def initialize
7
+ @attributes = {}
8
+ @attributes[:initialize_fields] = {}
9
+ @attributes[:report_fields] = {}
10
+ end
11
+
12
+ def initialize_fields *args, &block
13
+ if args.present?
14
+ args.each{|x| @attributes[:initialize_fields][x]}
15
+ end
16
+ if block_given?
17
+ attrs_factory = AttrsFactory.new
18
+ attrs_factory.instance_eval(&block)
19
+ @attributes[:initialize_fields].merge!(attrs_factory.attributes)
20
+ end
21
+ end
22
+
23
+ def field *names, &block
24
+ field_factory = ReportGenerator::Factories::ReportFieldFactory.new
25
+ field_factory.instance_eval(&block) if block_given?
26
+ @attributes[:report_fields][names] = field_factory.attributes
27
+ end
28
+
29
+ def method_missing(name, *args, &block)
30
+ @attributes[name] = args[0]
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ module ReportGenerator
2
+ module Factories
3
+ class ReportFieldFactory
4
+ attr_reader :attributes
5
+
6
+ def initialize
7
+ @attributes = {}
8
+ @attributes[:section_columns] = []
9
+ end
10
+
11
+ def section name
12
+ @attributes[:section] = name
13
+ end
14
+
15
+ def column column_name
16
+ @attributes[:section_columns] << column_name
17
+ end
18
+
19
+ def columns *args
20
+ @attributes[:section_columns] += args
21
+ end
22
+
23
+ def method_missing(name, *args, &block)
24
+ @attributes[name] = args
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,76 @@
1
+ module ReportGenerator
2
+ module Factories
3
+ class SectionFactory
4
+ attr_reader :attributes
5
+
6
+ def initialize
7
+ @attributes = {}
8
+ @attributes[:select_columns] = []
9
+ @attributes[:conditions] = []
10
+ @attributes[:group_columns] = []
11
+ @attributes[:sum_groups] = {}
12
+ @attributes[:joins] = []
13
+ end
14
+
15
+ def mixin section_name, options = {}
16
+ tmp_sf_attrs = ReportGenerator.section_factories[section_name].attributes.dup
17
+ except_items = options[:except]
18
+ if except_items
19
+ tmp_except_items = except_items.is_a?(Array) ? except_items : [except_items]
20
+ tmp_except_items.each{|x| tmp_sf_attrs.delete(x)}
21
+ end
22
+ @attributes.merge!(tmp_sf_attrs)
23
+ end
24
+
25
+ def data_source kclass
26
+ @attributes[:data_source] = kclass
27
+ end
28
+
29
+ def select *cols
30
+ @attributes[:select_columns] += cols
31
+ end
32
+
33
+ def count *cols
34
+ @attributes[:select_columns] += cols.collect do |x|
35
+ "COUNT(#{x}) count_#{x.to_s.gsub('.', '_')}"
36
+ end
37
+ end
38
+
39
+ def distinct_count *cols
40
+ @attributes[:select_columns] += cols.collect do |x|
41
+ "COUNT(DISTINCT #{x}) count_distinct_#{x.to_s.gsub('.', '_')}"
42
+ end
43
+ end
44
+
45
+ def sum *cols
46
+ @attributes[:select_columns] += cols.collect{|x| "SUM(#{x})"}
47
+ end
48
+
49
+ def condition *arg, &block
50
+ @attributes[:conditions] += arg
51
+ if block_given?
52
+ attrs_factory = AttrsFactory.new
53
+ attrs_factory.instance_eval(&block)
54
+ @attributes[:conditions] << attrs_factory.attributes
55
+ end
56
+ end
57
+
58
+ def group *arg
59
+ @attributes[:select_columns] += arg
60
+ @attributes[:group_columns] += arg
61
+ end
62
+
63
+ def sum_group col, manager = nil
64
+ @attributes[:sum_groups][col] = manager
65
+ end
66
+
67
+ def join join_clause
68
+ @attributes[:joins] << join_clause
69
+ end
70
+
71
+ def method_missing(name, *args, &block)
72
+ @attributes[name] = args[0]
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,13 @@
1
+ module ReportGenerator
2
+ module Helpers
3
+ module QueryBuilder
4
+ def query data_source, select_columns, joins, conditions, group_columns
5
+ result = data_source
6
+ result = data_source.select(select_columns) if select_columns.present?
7
+ joins.each{|x| result = result.joins(x)}
8
+ conditions.each{|x| result = result.where(x)}
9
+ result.group(group_columns)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,87 @@
1
+ module ReportGenerator
2
+ module Models
3
+ class Report
4
+ attr_accessor :name, :initialize_fields, :report_fields, :blank_init_fields, :fields_maps
5
+
6
+ def perform
7
+ prepare
8
+ integration_records = integrate_sections
9
+ grouped_records = gen_grouped_records(integration_records)
10
+ merged_records = merge_grouped_records(grouped_records)
11
+ save(merged_records)
12
+ end
13
+
14
+ private
15
+ def report_class
16
+ @name
17
+ end
18
+
19
+ def gen_initialize_fields report_field_name, record
20
+ result = @initialize_fields.dup
21
+ result.tap do |x|
22
+ @blank_init_fields.each_with_index do |blank_field_name, idx|
23
+ x[blank_field_name] = record.send(@fields_maps[report_field_name][blank_field_name])
24
+ end
25
+ end
26
+ end
27
+
28
+ def init_blank_init_fields
29
+ @blank_init_fields = @initialize_fields.collect{|k,v| k if v.blank?}.compact
30
+ end
31
+
32
+ def init_fields_maps
33
+ @fields_maps = {}.tap do |x|
34
+ @report_fields.each do |report_field_name, report_field_attrs|
35
+ tmp_report_fields = @blank_init_fields + report_field_name
36
+ x[report_field_name] = {}
37
+ tmp_report_fields.each_with_index do |field_name, idx|
38
+ x[report_field_name][field_name] = report_field_attrs[:section_columns][idx]
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ def prepare
45
+ init_blank_init_fields
46
+ init_fields_maps
47
+ end
48
+
49
+ def gen_grouped_records records
50
+ records.group_by{|r| r[:init_fields]}
51
+ end
52
+
53
+ def merge_grouped_records grouped_records
54
+ {}.tap do |x|
55
+ grouped_records.each do |group_key, records|
56
+ tmp_records = records.each{|x| x.delete(:init_fields)}
57
+ x[group_key]=tmp_records.inject(&:merge)
58
+ end
59
+ end
60
+ end
61
+
62
+ def integrate_sections
63
+ @report_fields.collect do |field_name, field_attrs|
64
+ section = ReportGenerator.build(ReportGenerator::Models::Section, field_attrs[:section])
65
+ records = section.perform
66
+ records.collect do |record|
67
+ r = {}.tap do |x|
68
+ x[:init_fields] = gen_initialize_fields(field_name, record)
69
+ field_name.each{|fn| x[fn] = record.send(@fields_maps[field_name][fn])}
70
+ end
71
+ end
72
+ end.flatten
73
+ end
74
+
75
+ def save records
76
+ ActiveRecord::Base.transaction do
77
+ records.each do |init_fields, record_attrs|
78
+ r = report_class.find_or_initialize_by(init_fields)
79
+ record_attrs.each{|k,v| r.send("#{k}=",v) }
80
+ r.save
81
+ end
82
+ end
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,7 @@
1
+ module ReportGenerator
2
+ module Models
3
+ class ReportField
4
+ attr_accessor :name, :section, :section_columns
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ module ReportGenerator
2
+ module Models
3
+ class Section
4
+ include ReportGenerator::Helpers::QueryBuilder
5
+ attr_accessor :name, :data_source, :select_columns, :joins, :conditions, :group_columns, :sum_groups
6
+
7
+ def perform
8
+ p "current_section: #{name}"
9
+ records = query(data_source, select_columns, joins, conditions, group_columns)
10
+ if sum_groups.present?
11
+ sum_records = sum_groups.collect do |sum_col, distributer|
12
+ tmp_sum_col = sum_col.to_s.split('.').last
13
+ sum_group_items = distributer.distribute(records.map(&tmp_sum_col.to_sym).uniq.compact)
14
+ tmp_group_columns,tmp_select_columns = group_columns.dup, select_columns.dup
15
+ tmp_group_columns.delete(sum_col)
16
+ tmp_select_columns.delete(sum_col)
17
+ sum_group_items.collect do |sum_group_item|
18
+ tmp_conditions = []
19
+ tmp_conditions = conditions.dup
20
+ group_name = sum_group_item.shift
21
+ tmp_conditions << {sum_col => sum_group_item} if sum_group_item.compact.present?
22
+ result = query(data_source, tmp_select_columns, joins, tmp_conditions,tmp_group_columns)
23
+ result.tap do |x|
24
+ x.collect! do|r|
25
+ tmp_attrs = r.attributes.dup
26
+ tmp_attrs[tmp_sum_col] = group_name
27
+ OpenStruct.new(tmp_attrs)
28
+ end
29
+ end
30
+ end # group_items
31
+ end # sum_groups
32
+ records += sum_records.flatten
33
+ end
34
+ records
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ module ReportGenerator
2
+ VERSION = "1.0.0.beta1"
3
+ end
@@ -0,0 +1,58 @@
1
+ require 'ostruct'
2
+
3
+ require 'report_generator/helpers/query_builder'
4
+ require 'report_generator/factories/attrs_factory'
5
+ require 'report_generator/factories/report_field_factory'
6
+ require 'report_generator/factories/section_factory'
7
+ require 'report_generator/factories/report_factory'
8
+ require 'report_generator/definers/section_definer'
9
+ require 'report_generator/definers/report_definer'
10
+ require 'report_generator/models/report'
11
+ require 'report_generator/models/report_field'
12
+ require 'report_generator/models/section'
13
+ require 'report_generator/version'
14
+
15
+ module ReportGenerator
16
+ @factories = {
17
+ ReportGenerator::Models::Section => {},
18
+ ReportGenerator::Models::Report => {}
19
+ }
20
+ class << self
21
+ def section_factories
22
+ @factories[ReportGenerator::Models::Section]
23
+ end
24
+
25
+ def report_factories
26
+ @factories[ReportGenerator::Models::Report]
27
+ end
28
+
29
+ def configure &block
30
+ class_eval(&block) if block_given?
31
+ end
32
+
33
+ def define_section &block
34
+ section_definer = ReportGenerator::Definers::SectionDefiner.new
35
+ section_definer.instance_eval(&block) if block_given?
36
+ end
37
+
38
+ def define_report &block
39
+ generator_definer = ReportGenerator::Definers::ReportDefiner.new
40
+ generator_definer.instance_eval(&block) if block_given?
41
+ end
42
+
43
+ def build model_class, name, attributes = {}
44
+ tmp_factory_attributes = @factories[model_class][name].attributes
45
+ if attributes.present?
46
+ tmp_factory_attributes.merge!(attributes)
47
+ end
48
+ tmp_model = model_class.new
49
+ tmp_model.tap do |x|
50
+ x.name = name
51
+ tmp_factory_attributes.each do |k,v|
52
+ x.send("#{k}=", v)
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'report_generator/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "report_generator"
8
+ spec.version = ReportGenerator::VERSION
9
+ spec.authors = ["Evan Chiu"]
10
+ spec.email = ["bjevanchiu@gmail.com"]
11
+ spec.description = %q{A simple Ruby Internal DSL for creating Count Report which save data from MySQL to MySQL.}
12
+ spec.summary = %q{A simple Ruby Internal DSL for creating Count Report which save data from MySQL to MySQL.}
13
+ spec.homepage = "https://github.com/bjevanchiu/report_generator"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: report_generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Evan Chiu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A simple Ruby Internal DSL for creating Count Report which save data
42
+ from MySQL to MySQL.
43
+ email:
44
+ - bjevanchiu@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - LICENSE
51
+ - README.md
52
+ - lib/report_generator.rb
53
+ - lib/report_generator/definers/report_definer.rb
54
+ - lib/report_generator/definers/section_definer.rb
55
+ - lib/report_generator/factories/attrs_factory.rb
56
+ - lib/report_generator/factories/report_factory.rb
57
+ - lib/report_generator/factories/report_field_factory.rb
58
+ - lib/report_generator/factories/section_factory.rb
59
+ - lib/report_generator/helpers/query_builder.rb
60
+ - lib/report_generator/models/report.rb
61
+ - lib/report_generator/models/report_field.rb
62
+ - lib/report_generator/models/section.rb
63
+ - lib/report_generator/version.rb
64
+ - report_generator.gemspec
65
+ homepage: https://github.com/bjevanchiu/report_generator
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.3.1
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 2.5.1
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: A simple Ruby Internal DSL for creating Count Report which save data from
89
+ MySQL to MySQL.
90
+ test_files: []