athergin 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
...
|