athergin 0.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +1 -0
- data/athergin.gemspec +21 -0
- data/lib/athergin.rb +10 -0
- data/lib/athergin/attribute.rb +10 -0
- data/lib/athergin/namespace.rb +69 -0
- data/lib/athergin/platform.rb +108 -0
- data/lib/athergin/query.rb +189 -0
- data/lib/athergin/report.rb +79 -0
- data/lib/athergin/transformer.rb +61 -0
- data/lib/athergin/version.rb +3 -0
- metadata +71 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Sarkis Karayan
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Athergin
|
2
|
+
|
3
|
+
Athergin Web Framework
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'athergin'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install athergin
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
30
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/athergin.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'athergin/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'athergin'
|
8
|
+
gem.version = Athergin::VERSION
|
9
|
+
gem.authors = ['Sarkis Karayan']
|
10
|
+
gem.email = ['skarayan@gmail.com']
|
11
|
+
gem.description = 'Athergin Web Framework'
|
12
|
+
gem.summary = 'Athergin Web Framework'
|
13
|
+
gem.homepage = 'https://github.com/skarayan/athergin'
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_dependency 'core_extensions'
|
21
|
+
end
|
data/lib/athergin.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Attribute
|
2
|
+
def attribute(*names)
|
3
|
+
names.each do |name|
|
4
|
+
instance_variable_name = :"@#{ name }"
|
5
|
+
define_method name do |value=nil|
|
6
|
+
value ? instance_variable_set(instance_variable_name,value) : instance_variable_get(instance_variable_name)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class Namespace
|
2
|
+
extend Attribute
|
3
|
+
attr_reader :reports, :transformers, :display_order
|
4
|
+
attribute :name, :description, :explanation
|
5
|
+
|
6
|
+
def to_h
|
7
|
+
methods = [:name, :description, :current?, :css_class_name, :report_objects]
|
8
|
+
methods.map do |method|
|
9
|
+
key, value = method.to_s.gsub(/\?$/,'').to_sym, send(method)
|
10
|
+
value = '' if value.nil?
|
11
|
+
value = value.to_data if value.is_a? Array
|
12
|
+
|
13
|
+
[key, value]
|
14
|
+
end.to_h
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def all
|
19
|
+
Platform.namespaces.values rescue []
|
20
|
+
end
|
21
|
+
|
22
|
+
def displayable
|
23
|
+
all.select { |n| n.report_objects.present? }.sort { |a,b| a.display_order <=> b.display_order }
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_by_name(name)
|
27
|
+
all.find { |namespace| namespace.name == name.try(:to_sym) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(name, display_order)
|
32
|
+
@name, @display_order = name, display_order
|
33
|
+
@reports = {}
|
34
|
+
@transformers = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
# todo: change this to reports
|
38
|
+
def report_objects
|
39
|
+
reports.values
|
40
|
+
end
|
41
|
+
|
42
|
+
# todo: change this to transformers
|
43
|
+
def transformer_objects
|
44
|
+
transformers.values
|
45
|
+
end
|
46
|
+
|
47
|
+
def report(name, &block)
|
48
|
+
warn "warning: overriding report '#{ name }'" if @reports[name]
|
49
|
+
|
50
|
+
@reports[name] = Report.new name, namespace: self
|
51
|
+
@reports[name].instance_eval &block
|
52
|
+
end
|
53
|
+
|
54
|
+
def transformer(name, &block)
|
55
|
+
warn "warning: overriding transformer '#{ name }'" if @transformers[name]
|
56
|
+
|
57
|
+
@transformers[name] = Transformer.new name
|
58
|
+
@transformers[name].instance_eval &block
|
59
|
+
end
|
60
|
+
|
61
|
+
def current?
|
62
|
+
name.eql? Platform.current_namespace.name
|
63
|
+
end
|
64
|
+
|
65
|
+
# todo: think this over, models are probably not a good place for the css class name
|
66
|
+
def css_class_name
|
67
|
+
current? ? 'active' : 'inactive'
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# todo: module Athergin
|
2
|
+
module Platform
|
3
|
+
class << self
|
4
|
+
attr_reader :config, :connections, :namespaces, :eval_queue
|
5
|
+
|
6
|
+
def load_config!(config_file='config/environment.yml')
|
7
|
+
@config = Configuration.new config_file
|
8
|
+
end
|
9
|
+
|
10
|
+
def connect!
|
11
|
+
@connections = {}
|
12
|
+
config.environments.each do |env|
|
13
|
+
database = config.database_config env
|
14
|
+
begin
|
15
|
+
pool_size, pool_timeout = database.pool_size || 50, database.pool_timeout || 60
|
16
|
+
if database.hosts.present?
|
17
|
+
@connections[env] = Mongo::ReplSetConnection.new database.hosts, pool_size: pool_size, pool_timeout: pool_timeout
|
18
|
+
else
|
19
|
+
@connections[env] = Mongo::Connection.new database.hostname, database.port, pool_size: pool_size, pool_timeout: pool_timeout
|
20
|
+
end
|
21
|
+
rescue Mongo::ConnectionFailure => e
|
22
|
+
warn "Warning (could not connect to the #{ env } environment, skipping): #{ e.message }"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def namespace(name, opts={}, &block)
|
28
|
+
file_execution_order = namespace_display_order = opts[:display_order] || 10_000
|
29
|
+
|
30
|
+
@namespaces = {} if @namespaces.nil?
|
31
|
+
@namespaces[name] = Namespace.new(name, namespace_display_order) if @namespaces[name].nil?
|
32
|
+
|
33
|
+
@eval_queue = [] if @eval_queue.nil?
|
34
|
+
@eval_queue << [file_execution_order, @namespaces[name], block]
|
35
|
+
end
|
36
|
+
|
37
|
+
# execute the files in the right order as specified in the reports directory (for display order in index page and menu)
|
38
|
+
def run_eval_queue!
|
39
|
+
eval_queue.sort { |a,b| a.first <=> b.first }.each do |file_execution_order,namespace,block|
|
40
|
+
namespace.instance_eval &block
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def params
|
45
|
+
Thread.current[:params]
|
46
|
+
end
|
47
|
+
|
48
|
+
def search_params
|
49
|
+
(params[:search] || {}).reject { |param,value| value.blank? }
|
50
|
+
end
|
51
|
+
|
52
|
+
def exact_match?
|
53
|
+
params[:exact_match].present?
|
54
|
+
end
|
55
|
+
|
56
|
+
def query_limit
|
57
|
+
params[:limit]
|
58
|
+
end
|
59
|
+
|
60
|
+
def query_offset
|
61
|
+
params[:offset]
|
62
|
+
end
|
63
|
+
|
64
|
+
def cookies
|
65
|
+
Thread.current[:cookies] || {}
|
66
|
+
end
|
67
|
+
|
68
|
+
def environment
|
69
|
+
@environment || cookies['environment'].try(:to_sym) || ENV['REPORTS_ENV'].try(:to_sym) || :development
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_environment!(env)
|
73
|
+
puts "Setting environment as #{ env }"
|
74
|
+
@environment = env.to_sym
|
75
|
+
end
|
76
|
+
|
77
|
+
def connected_environments
|
78
|
+
# todo: reverse is kind of ugly here
|
79
|
+
@connections.keys.reverse rescue []
|
80
|
+
end
|
81
|
+
|
82
|
+
def connection
|
83
|
+
@connections[environment]
|
84
|
+
end
|
85
|
+
|
86
|
+
def database_name(name)
|
87
|
+
database_name = Platform.config.database_override.try(name) || name
|
88
|
+
end
|
89
|
+
|
90
|
+
def database(name)
|
91
|
+
Platform.connection[database_name(name)]
|
92
|
+
end
|
93
|
+
|
94
|
+
def current_namespace
|
95
|
+
current_report.try(:namespace)
|
96
|
+
end
|
97
|
+
|
98
|
+
def current_report
|
99
|
+
return unless params[:type].eql? 'reports'
|
100
|
+
Report.find_by_name params[:name]
|
101
|
+
end
|
102
|
+
|
103
|
+
def current_query
|
104
|
+
return unless params[:type].eql? 'queries'
|
105
|
+
Query.find_by_name params[:name]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
class Query
|
2
|
+
extend Attribute
|
3
|
+
attribute :name, :description, :explanation, :database, :filters, :fields, :field_groups, :search_mapping
|
4
|
+
attr_accessor :partial_search_fields # todo: clean this up
|
5
|
+
attr_accessor :results_block, :query_block, :transform_block, :callback_blocks # todo: rename all these *_block attributes to remove the '_block' from the name
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# todo: change this to queries
|
9
|
+
def all
|
10
|
+
Report.all.map(&:query_objects).flatten
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_by_name(name)
|
14
|
+
all.find { |query| query.name == name.try(:to_sym) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(name)
|
19
|
+
@name = name
|
20
|
+
@fields = {}
|
21
|
+
@search_mapping = {}
|
22
|
+
@partial_search_fields = []
|
23
|
+
@default_sort_fields = {}
|
24
|
+
@filters = {}
|
25
|
+
@show_all_on_load = false
|
26
|
+
@transform_block = Proc.new { raise 'Please implement the transform block in your query.' }
|
27
|
+
@results_block = Proc.new { query.to_a.map { |row| self.instance_exec row, &transform_block } }
|
28
|
+
@callback_blocks = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def collection(name=nil)
|
32
|
+
if name
|
33
|
+
if name.is_a? Symbol
|
34
|
+
@collection = name
|
35
|
+
elsif name.is_a? String
|
36
|
+
db,tbl = name.split('/').map(&:to_sym)
|
37
|
+
database db
|
38
|
+
collection tbl
|
39
|
+
end
|
40
|
+
else
|
41
|
+
@collection
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# todo: change naming of this method to make it more consistent
|
46
|
+
def allow_partial_search_for(*fields)
|
47
|
+
@partial_search_fields = fields.map(&:to_sym)
|
48
|
+
end
|
49
|
+
|
50
|
+
# todo: refactor to use attribute for consistency
|
51
|
+
def limit_results_to(count)
|
52
|
+
@limit = count
|
53
|
+
end
|
54
|
+
|
55
|
+
def params
|
56
|
+
Platform.search_params
|
57
|
+
end
|
58
|
+
|
59
|
+
def limit
|
60
|
+
Platform.query_limit || @limit || 1000
|
61
|
+
end
|
62
|
+
|
63
|
+
def offset
|
64
|
+
Platform.query_offset || @offset || 0
|
65
|
+
end
|
66
|
+
|
67
|
+
def exact_match
|
68
|
+
Platform.exact_match? || @exact_match || false
|
69
|
+
end
|
70
|
+
|
71
|
+
def partial_match
|
72
|
+
!exact_match
|
73
|
+
end
|
74
|
+
|
75
|
+
# todo: remove to_sym (everywhere in code), use hash_with_indifferent_attributes
|
76
|
+
def allow_partial_match?(field=nil)
|
77
|
+
if field.present?
|
78
|
+
partial_match && partial_search_fields.include?(field.to_sym)
|
79
|
+
else
|
80
|
+
@partial_search_fields.present?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def where
|
85
|
+
params.map do |field,value|
|
86
|
+
field = search_mapping[field.to_sym]
|
87
|
+
next if field.nil?
|
88
|
+
|
89
|
+
value = /#{ value }/i if allow_partial_match? field
|
90
|
+
[field,value]
|
91
|
+
end.compact.to_h.merge @filters
|
92
|
+
end
|
93
|
+
|
94
|
+
# todo: refactor @filters and @default_sort_fields to method calls
|
95
|
+
def query
|
96
|
+
return self.instance_eval(&query_block) if query_block
|
97
|
+
|
98
|
+
# todo: add namespace and report name in error message
|
99
|
+
raise "No collection specified for '#{ name }'" if collection.nil?
|
100
|
+
raise "No database specified for '#{ name }'" if database.nil?
|
101
|
+
|
102
|
+
puts "find: #{ Platform.database_name(database.to_s) }/#{ collection } -> #{ where.inspect }"
|
103
|
+
Platform.database(database.to_s)[collection.to_s].find(where).sort(@default_sort_fields).limit(limit).skip(offset)
|
104
|
+
end
|
105
|
+
|
106
|
+
def define_query(&block)
|
107
|
+
@query_block = block
|
108
|
+
end
|
109
|
+
|
110
|
+
def results(&block)
|
111
|
+
@results_block = block
|
112
|
+
end
|
113
|
+
|
114
|
+
def transform(&block)
|
115
|
+
@transform_block = block
|
116
|
+
end
|
117
|
+
|
118
|
+
def data
|
119
|
+
self.instance_eval &results_block
|
120
|
+
end
|
121
|
+
|
122
|
+
# todo: rename for consistensy
|
123
|
+
def default_sort_by(sort_fields)
|
124
|
+
@default_sort_fields = sort_fields
|
125
|
+
end
|
126
|
+
|
127
|
+
# todo: review since it is redundant in both Report and Query
|
128
|
+
def show_all_on_load
|
129
|
+
@show_all_on_load = true
|
130
|
+
end
|
131
|
+
|
132
|
+
def require_search?
|
133
|
+
!show_all_on_load?
|
134
|
+
end
|
135
|
+
|
136
|
+
def show_all_on_load?
|
137
|
+
@show_all_on_load
|
138
|
+
end
|
139
|
+
|
140
|
+
def view_name
|
141
|
+
:query
|
142
|
+
end
|
143
|
+
|
144
|
+
def listen_for(callback,&block)
|
145
|
+
@callback_blocks[callback] = block
|
146
|
+
end
|
147
|
+
|
148
|
+
# todo: cleanup
|
149
|
+
=begin
|
150
|
+
def to_tsv
|
151
|
+
results.unshift(self.class.fields).map { |row| row.join("\t") }.join("\n")
|
152
|
+
end
|
153
|
+
|
154
|
+
def save(filename)
|
155
|
+
File.open(filename, 'w') { |f| f.write to_tsv }
|
156
|
+
end
|
157
|
+
|
158
|
+
class << self
|
159
|
+
def from(collection_name)
|
160
|
+
db,tbl = collection_name.split('/')
|
161
|
+
define_singleton_method(:from_database) { db }
|
162
|
+
define_singleton_method(:from_collection) { tbl }
|
163
|
+
end
|
164
|
+
|
165
|
+
def group_by(field_name)
|
166
|
+
define_singleton_method(:group_by_field) { field_name }
|
167
|
+
end
|
168
|
+
|
169
|
+
def aggregate(fields)
|
170
|
+
define_singleton_method(:aggregate_fields) { fields }
|
171
|
+
end
|
172
|
+
|
173
|
+
def javascript_aggregate_map_function
|
174
|
+
erb = File.read('mapreduce/aggregate_map.js.erb')
|
175
|
+
Erubis::Eruby.new(erb).result group_by: group_by_field, aggregate: aggregate_fields
|
176
|
+
end
|
177
|
+
|
178
|
+
def javascript_aggregate_reduce_function
|
179
|
+
erb = File.read('mapreduce/aggregate_reduce.js.erb')
|
180
|
+
Erubis::Eruby.new(erb).result aggregate: aggregate_fields
|
181
|
+
end
|
182
|
+
|
183
|
+
def run
|
184
|
+
m, r = javascript_aggregate_map_function, javascript_aggregate_reduce_function
|
185
|
+
Platform.database(from_database)[from_collection].map_reduce m, r, out: { replace: collection, db: database }
|
186
|
+
end
|
187
|
+
end
|
188
|
+
=end
|
189
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class Report
|
2
|
+
extend Attribute
|
3
|
+
attr_reader :queries, :namespace
|
4
|
+
attribute :name, :description, :explanation, :search_fields
|
5
|
+
|
6
|
+
def to_h
|
7
|
+
methods = [:name, :description, :url, :current?, :css_class_name]
|
8
|
+
methods.map do |method|
|
9
|
+
key, value = method.to_s.gsub(/\?$/,'').to_sym, send(method)
|
10
|
+
value = '' if value.nil?
|
11
|
+
value = value.to_data if value.is_a? Array
|
12
|
+
|
13
|
+
[key, value]
|
14
|
+
end.to_h
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# todo: change this to reports
|
19
|
+
def all
|
20
|
+
Namespace.all.map(&:report_objects).flatten
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_by_name(name)
|
24
|
+
all.find { |report| report.name == name.try(:to_sym) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(name,opts={})
|
29
|
+
@name = name
|
30
|
+
@namespace = opts[:namespace]
|
31
|
+
@queries = {}
|
32
|
+
@show_all_on_load = false
|
33
|
+
end
|
34
|
+
|
35
|
+
# todo: change this to queries
|
36
|
+
def query_objects
|
37
|
+
queries.values
|
38
|
+
end
|
39
|
+
|
40
|
+
def url
|
41
|
+
"/reports/#{ name }"
|
42
|
+
end
|
43
|
+
|
44
|
+
def query(name, &block)
|
45
|
+
warn "warning: overriding query '#{ name }'" if @queries[name]
|
46
|
+
|
47
|
+
@queries[name] = Query.new name
|
48
|
+
@queries[name].instance_eval &block
|
49
|
+
end
|
50
|
+
|
51
|
+
def show_all_on_load
|
52
|
+
@show_all_on_load = true
|
53
|
+
end
|
54
|
+
|
55
|
+
def require_search?
|
56
|
+
!show_all_on_load?
|
57
|
+
end
|
58
|
+
|
59
|
+
def show_all_on_load?
|
60
|
+
@show_all_on_load
|
61
|
+
end
|
62
|
+
|
63
|
+
def allow_partial_match?
|
64
|
+
query_objects.select { |query| query.allow_partial_match? }.present?
|
65
|
+
end
|
66
|
+
|
67
|
+
def view_name
|
68
|
+
:report
|
69
|
+
end
|
70
|
+
|
71
|
+
def current?
|
72
|
+
name.eql? Platform.current_report.name
|
73
|
+
end
|
74
|
+
|
75
|
+
# todo: think this over, models are probably not a good place for the css class name
|
76
|
+
def css_class_name
|
77
|
+
current? ? 'active' : 'inactive'
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Transformer
|
2
|
+
extend Attribute
|
3
|
+
attr_reader :maps
|
4
|
+
attribute :defaults, :reduce, :database
|
5
|
+
|
6
|
+
def initialize(name)
|
7
|
+
@maps, @reduce = [], []
|
8
|
+
end
|
9
|
+
|
10
|
+
def collection(name=nil)
|
11
|
+
if name
|
12
|
+
if name.is_a? Symbol
|
13
|
+
@collection = name
|
14
|
+
elsif name.is_a? String
|
15
|
+
db,tbl = name.split('/').map(&:to_sym)
|
16
|
+
database db
|
17
|
+
collection tbl
|
18
|
+
end
|
19
|
+
else
|
20
|
+
@collection
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def map(hash)
|
25
|
+
raise 'Please specify collection for Transformer map' if hash[:collection].nil?
|
26
|
+
raise 'Please specify values for Transformer map' if hash[:values].nil?
|
27
|
+
@maps.push hash
|
28
|
+
end
|
29
|
+
|
30
|
+
def sum(field)
|
31
|
+
"+= value.#{ field } ? value.#{ field } : 0"
|
32
|
+
end
|
33
|
+
|
34
|
+
def mongodb_map_functions
|
35
|
+
erb = File.read('mapreduce/mongodb_map.js.erb')
|
36
|
+
maps.map do |map|
|
37
|
+
database, collection = map[:collection].split('/')
|
38
|
+
function = Erubis::Eruby.new(erb).result keys: map[:keys], values: map[:values]
|
39
|
+
[database,collection,function]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def mongodb_reduce_function
|
44
|
+
erb = File.read('mapreduce/mongodb_reduce.js.erb')
|
45
|
+
Erubis::Eruby.new(erb).result defaults: defaults, fields: reduce
|
46
|
+
end
|
47
|
+
|
48
|
+
def run_mapreduce
|
49
|
+
puts "Dropping collection #{ Platform.database_name(database) }/#{ collection }"
|
50
|
+
Platform.database(database.to_s)[collection.to_s].drop
|
51
|
+
|
52
|
+
mongodb_map_functions.each do |map_database,map_collection,mongodb_map_function|
|
53
|
+
puts "Loading #{ Platform.database_name(database.to_s) }/#{ collection } from #{ Platform.database_name(map_database) }/#{ map_collection }"
|
54
|
+
Platform.database(map_database)[map_collection].map_reduce mongodb_map_function,
|
55
|
+
mongodb_reduce_function,
|
56
|
+
out: { reduce: collection.to_s, db: Platform.database_name(database.to_s) }
|
57
|
+
end
|
58
|
+
|
59
|
+
true
|
60
|
+
end
|
61
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: athergin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sarkis Karayan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-15 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: core_extensions
|
16
|
+
version_requirements: &2056 !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ! '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
none: false
|
22
|
+
requirement: *2056
|
23
|
+
prerelease: false
|
24
|
+
type: :runtime
|
25
|
+
description: Athergin Web Framework
|
26
|
+
email:
|
27
|
+
- skarayan@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- LICENSE.txt
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- athergin.gemspec
|
38
|
+
- lib/athergin.rb
|
39
|
+
- lib/athergin/attribute.rb
|
40
|
+
- lib/athergin/namespace.rb
|
41
|
+
- lib/athergin/platform.rb
|
42
|
+
- lib/athergin/query.rb
|
43
|
+
- lib/athergin/report.rb
|
44
|
+
- lib/athergin/transformer.rb
|
45
|
+
- lib/athergin/version.rb
|
46
|
+
homepage: https://github.com/skarayan/athergin
|
47
|
+
licenses: []
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
none: false
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
none: false
|
64
|
+
requirements: []
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.8.15
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Athergin Web Framework
|
70
|
+
test_files: []
|
71
|
+
...
|