mylookup 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6d2aec87813030f47044c072473c3ee422ee1852
4
+ data.tar.gz: d3e9aeec030a2fe15ae538151f6f3d73736fa754
5
+ SHA512:
6
+ metadata.gz: a868b087ef7d1014bf70053f05f9b0452010af16c43cf2c00dc5c4dd8a38bbeea3a1909be33eb941f2c6c18f7e9190c1ba52b644f46071090c24cd72e3ef375f
7
+ data.tar.gz: 4682498bb757620f6004a963e3cef126ae39cd33df0b701239015a0d3880220e617e7372ba15a5c465c87dae81277c75b3b170e7a0ae215c186ce266b03d3fe2
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "vlookup"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,30 @@
1
+ require 'mylookup'
2
+ require 'optparse'
3
+
4
+ options = {}
5
+ options_parser = OptionParser.new do |opts|
6
+ opts.on("-l", "--left LEFT", "Path to the Left Table") do |left|
7
+ options[:left] = left
8
+ end
9
+ opts.on("-r", "--right RIGHT", "Path to the Right Table") do |right|
10
+ options[:right] = right
11
+ end
12
+ opts.on("--lefton LEFTON", "Left Table's matching column") do |lefton|
13
+ options[:lefton] = lefton
14
+ end
15
+ opts.on("--righton RIGHTON", "Right Table's matching column") do |righton|
16
+ options[:righton] = righton
17
+ end
18
+ opts.on("--leftsheet LEFTSHEET", "Left Table's sheet name") do |leftsheet|
19
+ options[:leftsheet] = leftsheet
20
+ end
21
+ opts.on("--rightsheet RIGHTSHEET", "Right Table's sheet name") do |rightsheet|
22
+ options[:rightsheet] = rightsheet
23
+ end
24
+ opts.on("v", "--[no-]verbose", "Run verbosely") do |v|
25
+ options[:verbose] = v
26
+ end
27
+ end
28
+
29
+ options_parser.parse!
30
+ Mylookup.run(options)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,156 @@
1
+ require "mylookup/version"
2
+ require "mylookup/validator"
3
+ require "mylookup/processor"
4
+
5
+ #= Entry point to startup the application
6
+ module Mylookup
7
+
8
+ # Entry point method that starts the whole app
9
+ def self.run(opts)
10
+ validate_options opts
11
+ l_src = source_type opts[:left], opts[:leftsheet], :left
12
+ r_src = source_type opts[:right], opts[:rightsheet], :right
13
+ options = {
14
+ :left => opts[:left],
15
+ :right => opts[:right],
16
+ :lefton => opts[:lefton],
17
+ :righton => opts[:righton],
18
+ :leftsheet => opts[:leftsheet],
19
+ :rightsheet => opts[:rightsheet],
20
+ :verbose => opts[:verbose],
21
+ :l_src => l_src,
22
+ :r_src => r_src,
23
+ }
24
+ validate_sources l_src, r_src, options
25
+ processor = Processor.new(options)
26
+ processor.process
27
+ end
28
+
29
+ # Health check up on options entered
30
+ def self.validate_options opts
31
+ unless opts[:left]
32
+ puts "[Error]: Left database/file name must be defined"
33
+ exit
34
+ else
35
+ unless opts[:leftsheet]
36
+ puts "[Warning] : Left table name must be defined in case of source being MongoDB"
37
+ puts "[Warning--cont'd]: First/Default sheet is assumed to be Left Table/Sheet "
38
+ else
39
+ unless opts[:lefton]
40
+ puts "[Error]: Left table/sheet matching column must be defined"
41
+ exit
42
+ end
43
+ end
44
+ end
45
+ unless opts[:right]
46
+ puts "[Error]: Right Database/File name must be defined"
47
+ exit
48
+ else
49
+ unless opts[:rightsheet]
50
+ puts "[Warning] : Right Collection name must be defined in case of source being MongoDB"
51
+ puts "[Warning--cont'd]: First/Default Sheet is assumed to be Right Table/Sheet "
52
+ else
53
+ unless opts[:righton]
54
+ puts "[Error]: Right table/sheet matching column must be defined"
55
+ exit
56
+ end
57
+ end
58
+ end
59
+ return true
60
+ end
61
+
62
+ # Validates the existence of fields/sheets of the left and right tables
63
+ def self.validate_sources l_src, r_src, ops
64
+ l_path, l_tbl, l_col = ops[:left], ops[:leftsheet], ops[:lefton]
65
+ r_path, r_tbl, r_col = ops[:right], ops[:rightsheet], ops[:righton]
66
+ if l_src == :excel
67
+ sht_comment, col_comment = validate_excel_attribs(l_path, l_tbl, l_col, :left)
68
+ puts "[Info]: Left Table => #{sht_comment} | #{col_comment}" if ops[:verbose]
69
+ elsif l_src == :mongo
70
+ db = File.split(l_path)[1]
71
+ valid, comment = validate_mongo_field_existence l_tbl, db, l_col
72
+ puts "[Info]: Left Table => #{comment}" if ops[:verbose]
73
+ end
74
+ if r_src == :excel
75
+ sht_comment, col_comment = validate_excel_attribs(r_path, r_tbl, r_col, :right)
76
+ puts "[Info]: Right Table => #{sht_comment} | #{col_comment}" if ops[:verbose]
77
+ elsif r_src == :mongo
78
+ db = File.split(r_path)[1]
79
+ valid, comment = validate_mongo_field_existence r_tbl, db, r_col
80
+ puts "[Info]: Right Table => #{comment}" if ops[:verbose]
81
+ end
82
+ end
83
+
84
+ # Validates the existence of sheet and matching column in an excel file
85
+ def self.validate_excel_attribs path, sht_name, col_name, src_type
86
+ valid, sht_comment = validate_excel_sheet_existence sht_name, path
87
+ valid, col_comment = validate_excel_column_existence col_name, sht_name, path, src_type
88
+ return sht_comment, col_comment
89
+ end
90
+
91
+ # Validates and gives the type of the file whether it is an excel file or
92
+ # Mongo DB collection
93
+ def self.source_type file_name, sht, what_tbl
94
+ unless file_name
95
+ puts "[Error]: #{what_tbl.to_s.capitalize} Table's path must be given"
96
+ exit
97
+ else
98
+ valid, comment = validate_file_existence file_name, sht
99
+ comment =~ /mongodb/i ? :mongo : :excel
100
+ end
101
+ end
102
+
103
+ # Validates whether the given file does exist or not
104
+ def self.validate_file_existence path, sht
105
+ valid, comment = Validator::FileValidator.new(path, coll: sht).validate
106
+ unless valid
107
+ puts "[Error]: #{comment}"
108
+ exit
109
+ else
110
+ return valid, comment
111
+ end
112
+ end
113
+
114
+ # Validates whether the given sheet does exist or not
115
+ def self.validate_excel_sheet_existence sht, path
116
+ sht_name = sht
117
+ sht_name = 0 unless sht_name
118
+ validator = Validator::ExcelAttribValidator.new(path, sht_name)
119
+ valid, comment = validator.validate_sheet
120
+ unless valid
121
+ puts "[Error]: #{comment}"
122
+ exit
123
+ else
124
+ return valid, comment
125
+ end
126
+ end
127
+
128
+ # Validates whether the given column does exist or not
129
+ def self.validate_excel_column_existence col, sht, path, what_tbl
130
+ unless col
131
+ puts "[Error]: #{what_tbl.to_s.capitalize} Table's matching column must be given"
132
+ exit
133
+ end
134
+ validator = Validator::ExcelAttribValidator.new(path, sht)
135
+ valid, comment = validator.validate_column col
136
+ unless valid
137
+ puts "[Error]: #{comment}"
138
+ exit
139
+ else
140
+ return valid, comment
141
+ end
142
+ end
143
+
144
+ # Validates whether the given column does exist or not
145
+ def self.validate_mongo_field_existence coll_name, db_name, field
146
+ validator = Validator::MongoAttribValidator.new(coll_name, db_name, field)
147
+ valid, comment = validator.validate_field
148
+ unless valid
149
+ puts "[Error]: #{comment}"
150
+ exit
151
+ else
152
+ return valid, comment
153
+ end
154
+ end
155
+
156
+ end
@@ -0,0 +1,66 @@
1
+ #= Module containing connectors to databases
2
+
3
+ module Connector
4
+
5
+ #== Defines MongoDB connection properties
6
+ class MongoConnector
7
+ require 'mongo'
8
+
9
+ attr_accessor :client, :coll, :coll_name, :db_name, :host, :port
10
+
11
+ def initialize(coll_name, db_name: 'ccsdm', host: 'localhost', port: '27017')
12
+ @coll_name, @db_name, @host, @port = coll_name, db_name, host, port
13
+ Mongo::Logger.logger.level = Logger::WARN
14
+ @conn_str = @host + ':' + @port
15
+ @client = Mongo::Client.new([@conn_str], :database => @db_name)
16
+ @coll = @client[@coll_name]
17
+ end
18
+
19
+ # Queries and returns number of documents in the collection
20
+ def recs qry
21
+ @coll.find(qry).count
22
+ end
23
+
24
+ def collection_exists?
25
+ recs({}) > 0
26
+ end
27
+
28
+ def field_exists? field
29
+ @coll.find({}).projection({ '_id' => 0 }).limit(1).collect { |doc| doc }[0].keys.include? field
30
+ end
31
+
32
+ public :recs, :collection_exists?
33
+ end
34
+
35
+ class ExcelReadConnector
36
+ require 'roo'
37
+
38
+ def initialize(path)
39
+ @path = path
40
+ @wb = Roo::Excelx.new(@path)
41
+ @sheets = @wb.sheets
42
+ end
43
+
44
+ def sheet_exists? sht_name
45
+ @sheets.include? sht_name
46
+ end
47
+
48
+ def column_exists? sht, col_name
49
+ @wb.sheet(sht).row(1).include? col_name
50
+ end
51
+ end
52
+
53
+ class ExcelWriteConnector
54
+ require 'rubyXL'
55
+
56
+ attr_accessor :wb, :ws
57
+
58
+ def initialize(path)
59
+ @path = path
60
+ @wb = RubyXL::Workbook.new
61
+ @ws = @wb.worksheets[0]
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,61 @@
1
+ require 'mylookup/reader'
2
+ require 'mylookup/writer'
3
+
4
+ #= class containing the functionalities of handling the whole show
5
+ class Processor
6
+
7
+ def initialize(opts)
8
+ @l_db, @l_tbl, @l_on = opts[:left], opts[:leftsheet], opts[:lefton]
9
+ @r_db, @r_tbl, @r_on = opts[:right], opts[:rightsheet], opts[:righton]
10
+ @verbose = opts[:verbose]
11
+ @l_src, @r_src = opts[:l_src], opts[:r_src]
12
+ @l_reader, @r_reader = nil, nil
13
+ @l_data, @r_data, @matched, @unmatched = nil, nil, nil, nil
14
+ if @l_src == :excel
15
+ @l_reader = FileReader::Excel.new(@l_db, @l_tbl, @l_on)
16
+ else
17
+ @l_reader = FileReader::MongoDB.new(@l_on, @l_tbl, db_name: @l_db)
18
+ end
19
+ if @r_src == :excel
20
+ @r_reader = FileReader::Excel.new(@r_db, @r_tbl, @r_on)
21
+ else
22
+ @r_reader = FileReader::MongoDB.new(@r_on, @r_tbl, db_name: @r_db)
23
+ end
24
+ end
25
+
26
+ def process
27
+ puts "Processing initiating..."
28
+ read_data
29
+ mylookup
30
+ write_unmatched unless @unmatched.empty?
31
+ end
32
+
33
+ def mylookup
34
+ puts "Executing mylookup..."
35
+ @unmatched = @l_data - @r_data
36
+ @matched = @l_data - @unmatched
37
+ puts "[Info]: Left Table size: #{@l_data.size} row(s)"
38
+ puts "Matched: #{@matched.size} row(s) Unmatched: #{@unmatched.size} row(s)"
39
+ puts "Matched: #{(@matched.size.to_f*100/@l_data.size.to_f).round(2)}%"
40
+ end
41
+
42
+ def write_unmatched
43
+ writer = FileWriter::Excel.new('unmatched.xlsx', @unmatched, @l_on)
44
+ writer.write
45
+ end
46
+
47
+ def read_data
48
+ puts "Reading Left Table data..."
49
+ l_comment = @l_reader.read
50
+ @l_data = @l_reader.data
51
+ puts "Reading Right Table data..."
52
+ r_comment = @r_reader.read
53
+ @r_data = @r_reader.data
54
+ puts "[Info]: LEFT =>#{l_comment}"
55
+ puts "[Info]: RIGHT=>#{r_comment}"
56
+ end
57
+
58
+ private :read_data, :mylookup, :write_unmatched
59
+ public :process
60
+
61
+ end
@@ -0,0 +1,61 @@
1
+ require 'mylookup/connector'
2
+
3
+
4
+ #= Contains funtionalities of reading data
5
+ module FileReader
6
+
7
+ #== Contains the functionalities of reading Excel data
8
+ class Excel < Connector::ExcelReadConnector
9
+ attr_reader :data
10
+
11
+ def initialize(path, sht_name, col_name)
12
+ super(path)
13
+ @sht = @wb.sheet(sht_name)
14
+ @col = col_name
15
+ @data = nil
16
+ end
17
+
18
+ def read(match: {}, hide: {}, q_meth: :find)
19
+ aoa = @sht.parse(@col.to_sym => @col)
20
+ @data = aoa.collect { |item| item[@col.to_sym].to_s.downcase }
21
+ @data = @data.uniq
22
+ return "Excel Data contains #{@data.size} row(s)\nExcel First Record => #{@data[0]}"
23
+ end
24
+
25
+ public :read
26
+
27
+ end
28
+
29
+ #== Contains the reading functionalities of MongoDB data
30
+ class MongoDB < Connector::MongoConnector
31
+ attr_reader :data
32
+
33
+ def initialize(col_name, coll_name, db_name: 'ccsdm', host: 'localhost', port: '27017')
34
+ super(coll_name, db_name: db_name, host: host, port: port)
35
+ @col = col_name
36
+ @data = []
37
+ end
38
+
39
+ def read(hide: { '_id' => 0 }, q_meth: :agg, match: {})
40
+ if q_meth == :find
41
+ @coll.find(match).projection(hide).each do |doc|
42
+ @data = @data + [doc[@col].to_s.downcase]
43
+ end
44
+ @data = @data.uniq
45
+ elsif q_meth == :agg
46
+ qry = [
47
+ { '$match' => match },
48
+ { '$group' => { '_id' => { @col => '$' + @col } } },
49
+ { '$project' => { '_id' => 0, @col => '$_id.' + @col } }
50
+ ]
51
+ @coll.aggregate(qry).each do |doc|
52
+ @data = @data + [doc[@col].to_s.downcase]
53
+ end
54
+ end
55
+ return "Mongo Data contains #{@data.size} row(s)\nMongo First Record => #{@data[0]}"
56
+ end
57
+
58
+ public :read
59
+ end
60
+
61
+ end
@@ -0,0 +1,97 @@
1
+ #= Validation module to checks all the base rules in input options
2
+
3
+ require 'mylookup/connector'
4
+
5
+ module Validator
6
+
7
+ #== Excel file attributes and properties validator
8
+ class ExcelAttribValidator < Connector::ExcelReadConnector
9
+
10
+ def initialize(path, sht)
11
+ super(path)
12
+ @sht = sht
13
+ end
14
+
15
+ def validate_sheet
16
+ if sheet_exists? @sht
17
+ [true, "#{@sht} sheet in #{@path} exists"]
18
+ else
19
+ [false, "#{@sht} sheet in #{@path} DOES NOT exist!"]
20
+ end
21
+ end
22
+
23
+ def validate_column col_name
24
+ if column_exists? @sht, col_name
25
+ [true, "#{col_name} column in #{@sht} sheet of #{@path} exists"]
26
+ else
27
+ [false, "#{col_name} column in #{@sht} sheet of #{@path} DOES NOT exist!"]
28
+ end
29
+ end
30
+
31
+ public :validate_sheet, :validate_column
32
+
33
+ end
34
+
35
+ #== MongoDB collection attributes and properties validator
36
+ class MongoAttribValidator < Connector::MongoConnector
37
+
38
+ def initialize(coll_name, db, field)
39
+ super(coll_name, db_name: db)
40
+ @field = field
41
+ end
42
+
43
+ def validate_field
44
+ if field_exists? @field
45
+ [true, "'#{@field}' field exists in '#{@coll_name}' collection"]
46
+ else
47
+ [false, "'#{@field}' field DOES NOT exist in '#{@coll_name}' collection"]
48
+ end
49
+ end
50
+
51
+ public :validate_field
52
+
53
+ end
54
+
55
+ #== File Validator to validate the input paths of a file
56
+ class FileValidator
57
+
58
+ def initialize(path, coll: '')
59
+ @path = path
60
+ @coll = coll
61
+ end
62
+
63
+ def validate
64
+ if is_excel_file
65
+ if excel_file_exists
66
+ [true, "#{@path} does exist"]
67
+ else
68
+ return [false, "#{@path} does not exist"]
69
+ end
70
+ else
71
+ if @path =~ /\./i
72
+ return false, "#{@path} is neither an excel file nor a MongoDB collection"
73
+ else
74
+ db = File.split(@path)[1]
75
+ mongo_conn = Connector::MongoConnector.new(@coll, db_name: db)
76
+ unless mongo_conn.collection_exists?
77
+ return [false, "'#{@path}' collection in MongoDB does not exist"]
78
+ else
79
+ return true, "'#{@path}' is a MongoDB collection"
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def excel_file_exists
86
+ File.file?(@path)
87
+ end
88
+
89
+ def is_excel_file
90
+ @path[-5, 5] == '.xlsx'
91
+ end
92
+
93
+ private :is_excel_file, :excel_file_exists
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,3 @@
1
+ module Mylookup
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,43 @@
1
+ require 'mylookup/connector'
2
+
3
+
4
+ #=Contains functionalities of writing data
5
+ module FileWriter
6
+
7
+ #== Contains the functionalities of writing data in Excel
8
+ class Excel < Connector::ExcelWriteConnector
9
+
10
+ def initialize(path, data, header)
11
+ super(path)
12
+ @data = data
13
+ @header = header
14
+ end
15
+
16
+ def write
17
+ puts "Writing Data in Excel"
18
+ begin
19
+ write_header
20
+ write_data
21
+ rescue StandardError => err
22
+ puts "[Error]: Error occured while writing in Excel!!!"
23
+ puts err
24
+ end
25
+ end
26
+
27
+ def write_header
28
+ @ws.add_cell(0, 0, @header)
29
+ end
30
+
31
+ def write_data
32
+ @data.each_with_index do |d, i|
33
+ @ws.add_cell(i+1, 0, d.to_s.upcase)
34
+ end
35
+ @wb.write(@path)
36
+ end
37
+
38
+ private :write_header, :write_data
39
+ public :write
40
+ end
41
+
42
+ end
43
+
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mylookup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - jeyaraj
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-08-18 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.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
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: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubyXL
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.3'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 3.3.26
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '3.3'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 3.3.26
75
+ - !ruby/object:Gem::Dependency
76
+ name: roo
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.7'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 2.7.0
85
+ type: :development
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '2.7'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 2.7.0
95
+ - !ruby/object:Gem::Dependency
96
+ name: mongo
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '2.4'
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 2.4.1
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '2.4'
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 2.4.1
115
+ description: Does mylookup on Excel file or MongoDB collections
116
+ email:
117
+ - jeyaraj.durairaj@gmail.com
118
+ executables:
119
+ - console
120
+ - mylookup
121
+ - setup
122
+ extensions: []
123
+ extra_rdoc_files: []
124
+ files:
125
+ - bin/console
126
+ - bin/mylookup
127
+ - bin/setup
128
+ - lib/mylookup.rb
129
+ - lib/mylookup/connector.rb
130
+ - lib/mylookup/processor.rb
131
+ - lib/mylookup/reader.rb
132
+ - lib/mylookup/validator.rb
133
+ - lib/mylookup/version.rb
134
+ - lib/mylookup/writer.rb
135
+ homepage: https://github.com/jeydurai/mylookup
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.6.12
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: Simulates Excel's Mylookup function
159
+ test_files: []