messenger_pigeon 0.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +227 -0
- data/bin/messenger-pigeon +6 -0
- data/lib/messenger_pigeon/cli.rb +20 -0
- data/lib/messenger_pigeon/config.rb +14 -0
- data/lib/messenger_pigeon/console.rb +25 -0
- data/lib/messenger_pigeon/csv.rb +52 -0
- data/lib/messenger_pigeon/orgmode.rb +56 -0
- data/lib/messenger_pigeon/pigeon.rb +59 -0
- data/lib/messenger_pigeon/redmine.rb +78 -0
- data/lib/messenger_pigeon/version.rb +3 -0
- data/lib/messenger_pigeon.rb +38 -0
- metadata +102 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9fdb8c895d8bb1bcbe17ca6b03c1c5b9d5817f5a
|
4
|
+
data.tar.gz: 00b928c5bdb4bbdeda14f782c444ebb3c41579b4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 99d56f47b366c771b0cd3cb1fe5c22943d2807dd26fd863e0a785aa0636fb08f0165b8738374ea5da40a383034422497ff319db63aa1bb5c2aefba1e2a226dd0
|
7
|
+
data.tar.gz: 23e2a014dd88653a1e4f511f841221036fc254ce62e58d612aac538f02b44f3a09551cb4092d4bf862605a5c22a46e13b642bbd61db0b486cb30dafdcdf8efea
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Chris Mann
|
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,227 @@
|
|
1
|
+
# MessengerPigeon
|
2
|
+
|
3
|
+
A means of getting data from one location to another.
|
4
|
+
|
5
|
+
The goal of MessengerPigeon is to provide a highly-configurable and adaptable
|
6
|
+
animal to take data from any number of sources, and copy that data to any
|
7
|
+
number of destinations. A pigeon may modify, drop or add to your data while
|
8
|
+
in transit, but should only do these things when you ask it nicely.
|
9
|
+
|
10
|
+
MessengerPigeon is under heavy development.
|
11
|
+
|
12
|
+
## Configuration
|
13
|
+
Example Configuration demonstrating some features:
|
14
|
+
|
15
|
+
* CSV source to an OrgMode target
|
16
|
+
* Setting the data format for a target
|
17
|
+
* Globbed file selection
|
18
|
+
* Source hooks
|
19
|
+
* Data Filtering
|
20
|
+
* Pre and Post-filter data transformations
|
21
|
+
|
22
|
+
~/.messengerpigeonrc:
|
23
|
+
```ruby
|
24
|
+
{
|
25
|
+
targets: {
|
26
|
+
'OrgMode' => {
|
27
|
+
type: MessengerPigeon::OrgMode,
|
28
|
+
options: {
|
29
|
+
file: 'clocks.org',
|
30
|
+
refile_target: '%{project}',
|
31
|
+
data_format: proc do |d|
|
32
|
+
clock = ' CLOCK: [%{date} %{start_time}]--[%{date} %{end_time}] => %{duration}'
|
33
|
+
clock % d
|
34
|
+
end
|
35
|
+
}
|
36
|
+
}
|
37
|
+
},
|
38
|
+
sources: {
|
39
|
+
'TimeTracker' => {
|
40
|
+
type: MessengerPigeon::CSV,
|
41
|
+
options: {
|
42
|
+
file_glob: 'test.csv',
|
43
|
+
on_complete: :archive
|
44
|
+
}
|
45
|
+
}
|
46
|
+
},
|
47
|
+
pigeons: {
|
48
|
+
'Gemima' => {
|
49
|
+
source: 'TimeTracker',
|
50
|
+
filters: {
|
51
|
+
project: "Work"
|
52
|
+
},
|
53
|
+
transforms: {
|
54
|
+
pre_filter: {
|
55
|
+
date: proc { |a| Date.parse(a).strftime('%Y-%m-%d') },
|
56
|
+
duration: proc do |a|
|
57
|
+
r = format('%.2f', a.to_i + (a.to_f - a.to_i) / 100 * 60)
|
58
|
+
r.sub(/\./, ':')
|
59
|
+
end
|
60
|
+
},
|
61
|
+
post_filter: {}
|
62
|
+
},
|
63
|
+
target: 'OrgMode'
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
```
|
68
|
+
|
69
|
+
## Modules
|
70
|
+
|
71
|
+
### CSV
|
72
|
+
#### Source
|
73
|
+
```ruby
|
74
|
+
...
|
75
|
+
sources: {
|
76
|
+
'TimeTracker' => {
|
77
|
+
type: MessengerPigeon::CSV,
|
78
|
+
options: {
|
79
|
+
file_glob: 'test.csv',
|
80
|
+
on_complete: :archive
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
...
|
85
|
+
```
|
86
|
+
#### Target
|
87
|
+
Not yet implemented
|
88
|
+
|
89
|
+
### Console
|
90
|
+
#### Source
|
91
|
+
Not yet implemented.
|
92
|
+
#### Target
|
93
|
+
```ruby
|
94
|
+
...
|
95
|
+
targets: {
|
96
|
+
'Console => {
|
97
|
+
type: MessengerPigeon::Console,
|
98
|
+
options: {}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
...
|
102
|
+
```
|
103
|
+
### OrgMode
|
104
|
+
#### Source
|
105
|
+
Not yet implemented
|
106
|
+
#### Target
|
107
|
+
```ruby
|
108
|
+
...
|
109
|
+
targets: {
|
110
|
+
'OrgMode' => {
|
111
|
+
type: MessengerPigeon::OrgMode,
|
112
|
+
options: {
|
113
|
+
file: 'clocks.org',
|
114
|
+
refile_target: '%{project}',
|
115
|
+
data_format: proc do |d|
|
116
|
+
clock = ' CLOCK: [%{date} %{start_time}]--[%{date} %{end_time}] => %{duration}'
|
117
|
+
clock % d
|
118
|
+
end
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
...
|
123
|
+
```
|
124
|
+
### Redmine
|
125
|
+
Configuration should be self-explanatory except for perhaps the 'resource'
|
126
|
+
option. This is required option that corresponds to a capitalised,
|
127
|
+
camel-cased and singular equivalent to the resources listed here:
|
128
|
+
|
129
|
+
http://www.redmine.org/projects/redmine/wiki/Rest_api
|
130
|
+
|
131
|
+
E.g., 'time_entries' becomes 'TimeEntry'
|
132
|
+
#### Source
|
133
|
+
'mode' is either ':all', or ':specific'.
|
134
|
+
|
135
|
+
Example for :all to get all issues in Project 2.
|
136
|
+
```ruby
|
137
|
+
...
|
138
|
+
sources: {
|
139
|
+
'Redmine' => {
|
140
|
+
type: MessengerPigeon::Redmine,
|
141
|
+
options: {
|
142
|
+
resource: "Issue",
|
143
|
+
site: 'https://url.to.redmine.org',
|
144
|
+
user: 'username',
|
145
|
+
password: 's3kr1t'
|
146
|
+
mode: :all,
|
147
|
+
params: {
|
148
|
+
status_id: '*',
|
149
|
+
project_id: '2'
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
},
|
154
|
+
...
|
155
|
+
```
|
156
|
+
|
157
|
+
Example for :specific to get the issue with ID = 30
|
158
|
+
```ruby
|
159
|
+
...
|
160
|
+
sources: {
|
161
|
+
'Redmine' => {
|
162
|
+
type: MessengerPigeon::Redmine,
|
163
|
+
options: {
|
164
|
+
resource: "Issue",
|
165
|
+
site: 'https://url.to.redmine.org',
|
166
|
+
user: 'username',
|
167
|
+
password: 's3kr1t'
|
168
|
+
mode: :specific,
|
169
|
+
key: 30
|
170
|
+
}
|
171
|
+
}
|
172
|
+
},
|
173
|
+
...
|
174
|
+
```
|
175
|
+
|
176
|
+
#### Target
|
177
|
+
Note: The generators section of the configuration creates keys in the hash. This
|
178
|
+
should give a reasonable overview of what is required. See the description of
|
179
|
+
keys required on the particular resource page for more information.
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
...
|
183
|
+
targets: {
|
184
|
+
'Redmine' => {
|
185
|
+
type: MessengerPigeon::Redmine,
|
186
|
+
options: {
|
187
|
+
resource: "TimeEntry",
|
188
|
+
site: 'https://url.to.redmine.org',
|
189
|
+
user: 'username',
|
190
|
+
password: 's3kr1t'
|
191
|
+
}
|
192
|
+
},
|
193
|
+
},
|
194
|
+
pigeons: {
|
195
|
+
'Gemima' => {
|
196
|
+
filters: {
|
197
|
+
issue_id: proc { |a| !a.nil? },
|
198
|
+
activity_id: proc { |a| !a.nil? }
|
199
|
+
},
|
200
|
+
generators: {
|
201
|
+
activity_id: proc { |a| a[:activity_id] || '9' },
|
202
|
+
issue_id: proc do |a|
|
203
|
+
if a[:description]
|
204
|
+
m = a[:description].match(/\#(?<id>[0-9]+)/)
|
205
|
+
m[:id]
|
206
|
+
end
|
207
|
+
end,
|
208
|
+
hours: proc { |a| a[:duration] },
|
209
|
+
spent_on: proc { |a| a[:date] },
|
210
|
+
comments: proc do |a|
|
211
|
+
a[:description].sub(/\#[0-9]+ */, '') if a[:description]
|
212
|
+
end
|
213
|
+
},
|
214
|
+
transforms: {
|
215
|
+
pre_filter: {
|
216
|
+
date: proc { |a| Date.parse(a).strftime('%Y-%m-%d') }
|
217
|
+
},
|
218
|
+
post_filter: {}
|
219
|
+
},
|
220
|
+
source: 'MySource',
|
221
|
+
target: 'Redmine'
|
222
|
+
}
|
223
|
+
}
|
224
|
+
...
|
225
|
+
```
|
226
|
+
### And more?
|
227
|
+
Suggestions / contributions of more modules are welcome
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MessengerPigeon
|
2
|
+
module CLI
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def parse_options
|
6
|
+
options = {
|
7
|
+
config: File.expand_path(ENV['MESSENGER_PIGEON_RC'] ||
|
8
|
+
'~/.messenger-pigeon.rc')
|
9
|
+
}
|
10
|
+
OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
|
12
|
+
opts.on('-c', '--config file', 'Configuration file') do |f|
|
13
|
+
options[:config] = f
|
14
|
+
end
|
15
|
+
end.parse!
|
16
|
+
Config.pigeons = ARGV
|
17
|
+
options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
module MessengerPigeon
|
3
|
+
# Console source/target module
|
4
|
+
module Console
|
5
|
+
# Source definition
|
6
|
+
class Source
|
7
|
+
def initialize
|
8
|
+
fail 'Not Implemented'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Target definition
|
13
|
+
class Target
|
14
|
+
def initialize(_options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def update(data)
|
18
|
+
puts data
|
19
|
+
end
|
20
|
+
|
21
|
+
def write
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'csv'
|
2
|
+
CSVLib = CSV
|
3
|
+
module MessengerPigeon
|
4
|
+
# CSV source/target module
|
5
|
+
module CSV
|
6
|
+
# Source definition
|
7
|
+
class Source
|
8
|
+
def initialize(options)
|
9
|
+
# :file_glob
|
10
|
+
@files = Dir.glob(options[:file_glob])
|
11
|
+
@on_complete = options[:on_complete]
|
12
|
+
end
|
13
|
+
|
14
|
+
def read
|
15
|
+
@data = @files.collect { |f| read_file f }.flatten
|
16
|
+
end
|
17
|
+
|
18
|
+
def complete
|
19
|
+
case @on_complete
|
20
|
+
when :archive
|
21
|
+
archive_files
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def archive_files
|
28
|
+
@files.each do |f|
|
29
|
+
archive_dir = (File.dirname f) + '/archive/'
|
30
|
+
Dir.mkdir archive_dir unless Dir.exist? archive_dir
|
31
|
+
File.rename f, archive_dir + (File.basename f)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def read_file(file)
|
36
|
+
d = CSVLib.read file
|
37
|
+
headings = d.first.collect do |v|
|
38
|
+
title = v.gsub(/[^a-z]+/i, '_')
|
39
|
+
title.downcase.intern
|
40
|
+
end
|
41
|
+
d[1..-1].collect { |v| (headings.zip v).to_h }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Target definition
|
46
|
+
class Target
|
47
|
+
def initialize
|
48
|
+
fail 'Not Implemented'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module MessengerPigeon
|
4
|
+
# OrgMode source/target module
|
5
|
+
module OrgMode
|
6
|
+
# Source definition
|
7
|
+
class Source
|
8
|
+
def initialize(_options = {})
|
9
|
+
fail 'Not Implemented'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Target definition
|
14
|
+
class Target
|
15
|
+
def initialize(options = nil)
|
16
|
+
@options = options
|
17
|
+
if File.exist? options[:file]
|
18
|
+
@fd = File.open(options[:file], 'r+')
|
19
|
+
@fd.seek 0
|
20
|
+
@filedata = @fd.read nil
|
21
|
+
else
|
22
|
+
@fd = File.open(options[:file], 'w')
|
23
|
+
@filedata = ''
|
24
|
+
end
|
25
|
+
@known_headings = known_headings
|
26
|
+
end
|
27
|
+
|
28
|
+
def known_headings
|
29
|
+
res = []
|
30
|
+
@filedata.each_line do |l|
|
31
|
+
/^\*+\ (?<heading>.+?)(:[^ ]*:)?$/ =~ l
|
32
|
+
res.push heading if heading
|
33
|
+
end
|
34
|
+
res
|
35
|
+
end
|
36
|
+
|
37
|
+
def update(data)
|
38
|
+
heading = @options[:refile_target] % data
|
39
|
+
data_string = @options[:data_format].call data
|
40
|
+
if @known_headings.include? heading
|
41
|
+
@filedata.sub!(/^(\* #{heading}.*)$/,
|
42
|
+
"\\1\n#{data_string}")
|
43
|
+
else
|
44
|
+
@filedata += "* #{heading}\n#{data_string}\n"
|
45
|
+
@known_headings.push heading
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def write
|
50
|
+
@fd.seek 0
|
51
|
+
@fd.write @filedata
|
52
|
+
@fd.close
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
module MessengerPigeon
|
3
|
+
# Check and apply data matches
|
4
|
+
class Pigeon
|
5
|
+
def initialize(source, target, pigeon_config)
|
6
|
+
@source = source
|
7
|
+
@target = target
|
8
|
+
@filters = pigeon_config[:filters]
|
9
|
+
@transforms = pigeon_config[:transforms]
|
10
|
+
@generators = pigeon_config[:generators]
|
11
|
+
end
|
12
|
+
|
13
|
+
def fly
|
14
|
+
@source.read.each do |d|
|
15
|
+
transforms :pre_filter, d
|
16
|
+
generators d
|
17
|
+
@target.update(transforms :post_filter, d) if filter d
|
18
|
+
end
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def finalise
|
23
|
+
@target.write
|
24
|
+
@source.complete
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def filter(data)
|
30
|
+
return if @filters.nil?
|
31
|
+
@filters.each do |k, v|
|
32
|
+
if v.class == Regexp
|
33
|
+
return false unless data[k] =~ v
|
34
|
+
elsif v.class == String
|
35
|
+
return false unless data[k] == v
|
36
|
+
elsif v.class == Proc
|
37
|
+
return false unless v.call data[k]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
def transforms(type, data)
|
44
|
+
return data if @transforms.nil? || @transforms[:type].nil?
|
45
|
+
@transforms[type].each do |k, v|
|
46
|
+
data[k] = v.call data[k]
|
47
|
+
end
|
48
|
+
data
|
49
|
+
end
|
50
|
+
|
51
|
+
def generators(data)
|
52
|
+
return data if @generators.nil?
|
53
|
+
@generators.each do |k, v|
|
54
|
+
data[k] = v.call data
|
55
|
+
end
|
56
|
+
data
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'active_resource'
|
2
|
+
|
3
|
+
module MessengerPigeon
|
4
|
+
# Redmine source/target module
|
5
|
+
module Redmine
|
6
|
+
# Handle JSON returned by Redmine
|
7
|
+
class RedmineFormatter
|
8
|
+
include ActiveResource::Formats::JsonFormat
|
9
|
+
|
10
|
+
def decode(json)
|
11
|
+
remove_root(ActiveSupport::JSON.decode(json))
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def remove_root(data)
|
17
|
+
# Just return the first value in the hash
|
18
|
+
data.each do |_k, v|
|
19
|
+
return v
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Source definition
|
25
|
+
class Source
|
26
|
+
def initialize(options)
|
27
|
+
@options = options
|
28
|
+
ar_cl = Class.new ActiveResource::Base
|
29
|
+
o = Object.const_set(options[:resource], ar_cl)
|
30
|
+
o.site = options[:site]
|
31
|
+
o.user = options[:user]
|
32
|
+
o.password = options[:password]
|
33
|
+
o.include_root_in_json = true
|
34
|
+
o.format = RedmineFormatter.new
|
35
|
+
@resource = o
|
36
|
+
end
|
37
|
+
|
38
|
+
def read
|
39
|
+
if @options[:mode] == :specific
|
40
|
+
[@resource.find(@options[:key]).attributes]
|
41
|
+
elsif @options[:mode] == :all
|
42
|
+
res = @resource.find(:all, params: @options[:params])
|
43
|
+
res.map do |r|
|
44
|
+
attrs = r.attributes
|
45
|
+
attrs.each do |k, v|
|
46
|
+
attrs[k] = v.attributes if v.respond_to? :attributes
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def complete
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Target definition
|
57
|
+
class Target
|
58
|
+
def initialize(options)
|
59
|
+
@options = options
|
60
|
+
ar_cl = Class.new ActiveResource::Base
|
61
|
+
o = Object.const_set(options[:resource], ar_cl)
|
62
|
+
o.site = options[:site]
|
63
|
+
o.user = options[:user]
|
64
|
+
o.password = options[:password]
|
65
|
+
o.include_root_in_json = true
|
66
|
+
@resource = o
|
67
|
+
end
|
68
|
+
|
69
|
+
def update(data)
|
70
|
+
m = @resource.new data
|
71
|
+
$stderr.puts issue.errors.full_messages unless m.save
|
72
|
+
end
|
73
|
+
|
74
|
+
def write
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
require 'messenger_pigeon/version'
|
4
|
+
require 'messenger_pigeon/pigeon'
|
5
|
+
require 'messenger_pigeon/orgmode'
|
6
|
+
require 'messenger_pigeon/csv'
|
7
|
+
require 'messenger_pigeon/redmine'
|
8
|
+
require 'messenger_pigeon/console'
|
9
|
+
require 'messenger_pigeon/config'
|
10
|
+
require 'messenger_pigeon/cli'
|
11
|
+
|
12
|
+
# Messenger Pigeon entry
|
13
|
+
module MessengerPigeon
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def flock(opts)
|
17
|
+
Config.load(opts[:config])
|
18
|
+
pigeons = []
|
19
|
+
Config.conf[:pigeons].each do |name, instr|
|
20
|
+
next unless Config.pigeons.empty? || Config.pigeons.include?(name)
|
21
|
+
s = prepare_endpoint :sources, instr[:source]
|
22
|
+
t = prepare_endpoint :targets, instr[:target]
|
23
|
+
pigeon = Pigeon.new s, t, instr
|
24
|
+
pigeons << pigeon.fly
|
25
|
+
end
|
26
|
+
pigeons.each(&:finalise)
|
27
|
+
end
|
28
|
+
|
29
|
+
def prepare_endpoint(endpoint, name)
|
30
|
+
v = Config.conf[endpoint][name]
|
31
|
+
m = v[:type]
|
32
|
+
if endpoint == :sources
|
33
|
+
m::Source.new v[:options]
|
34
|
+
elsif endpoint == :targets
|
35
|
+
m::Target.new v[:options]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: messenger_pigeon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Mann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-10 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.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activeresource
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.0'
|
55
|
+
description: The goal of MessengerPigeon is to provide a highly-configurable and general
|
56
|
+
mechanism to take data from any number of sources, and copy that data to any number
|
57
|
+
of destinations. Possibly after some modest filtering and transformations.
|
58
|
+
email:
|
59
|
+
- chris@bitpattern.com.au
|
60
|
+
executables:
|
61
|
+
- messenger-pigeon
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- bin/messenger-pigeon
|
68
|
+
- lib/messenger_pigeon.rb
|
69
|
+
- lib/messenger_pigeon/cli.rb
|
70
|
+
- lib/messenger_pigeon/config.rb
|
71
|
+
- lib/messenger_pigeon/console.rb
|
72
|
+
- lib/messenger_pigeon/csv.rb
|
73
|
+
- lib/messenger_pigeon/orgmode.rb
|
74
|
+
- lib/messenger_pigeon/pigeon.rb
|
75
|
+
- lib/messenger_pigeon/redmine.rb
|
76
|
+
- lib/messenger_pigeon/version.rb
|
77
|
+
homepage: https://github.com/cshclm/MessengerPigeon
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.4.5
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: A means of getting data from one location to another.
|
101
|
+
test_files: []
|
102
|
+
has_rdoc:
|