unit_validator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,2 @@
1
+ require 'autotest/growl'
2
+ require 'autotest/fsevent'
data/.gitignore ADDED
@@ -0,0 +1,43 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ # jeweler generated
15
+ pkg
16
+
17
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
18
+ #
19
+ # * Create a file at ~/.gitignore
20
+ # * Include files you want ignored
21
+ # * Run: git config --global core.excludesfile ~/.gitignore
22
+ #
23
+ # After doing this, these files will be ignored in all your git projects,
24
+ # saving you from having to 'pollute' every project you touch with them
25
+ #
26
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
27
+ #
28
+ # For MacOS:
29
+ #
30
+ .DS_Store
31
+ #
32
+ # For TextMate
33
+ *.tmproj
34
+ tmtags
35
+ #
36
+ # For emacs:
37
+ #*~
38
+ #\#*
39
+ #.\#*
40
+ #
41
+ # For vim:
42
+ *.swp
43
+ .~*
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem 'roo'
5
+ gem 'zip'
6
+ gem 'spreadsheet'
7
+ gem 'nokogiri'
8
+ gem 'google-spreadsheet-ruby'
9
+ gem 'activesupport'
10
+ gem 'fastercsv'
11
+
12
+ gem 'autotest-fsevent', '>=0.2.2'
13
+ gem 'autotest-growl', '>=0.2.4'
14
+ gem 'builder'
15
+ gem "rspec", ">= 2.0.0.rc"
16
+ gem "bundler", "~> 1.0.0"
17
+ gem "jeweler", "~> 1.5.0.pre3"
18
+ gem "rcov"
19
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.0.1)
5
+ autotest-fsevent (0.2.3)
6
+ sys-uname
7
+ autotest-growl (0.2.6)
8
+ builder (2.1.2)
9
+ diff-lcs (1.1.2)
10
+ fastercsv (1.5.3)
11
+ git (1.2.5)
12
+ google-spreadsheet-ruby (0.1.2)
13
+ nokogiri (>= 1.4.3.1)
14
+ oauth (>= 0.3.6)
15
+ jeweler (1.5.0.pre3)
16
+ bundler (~> 1.0.0)
17
+ git (>= 1.2.5)
18
+ rake
19
+ nokogiri (1.4.3.1)
20
+ oauth (0.4.3)
21
+ rake (0.8.7)
22
+ rcov (0.9.9)
23
+ roo (1.9.3)
24
+ rspec (2.0.0.rc)
25
+ rspec-core (= 2.0.0.rc)
26
+ rspec-expectations (= 2.0.0.rc)
27
+ rspec-mocks (= 2.0.0.rc)
28
+ rspec-core (2.0.0.rc)
29
+ rspec-expectations (2.0.0.rc)
30
+ diff-lcs (>= 1.1.2)
31
+ rspec-mocks (2.0.0.rc)
32
+ rspec-core (= 2.0.0.rc)
33
+ rspec-expectations (= 2.0.0.rc)
34
+ ruby-ole (1.2.11)
35
+ spreadsheet (0.6.4.1)
36
+ ruby-ole
37
+ sys-uname (0.8.4)
38
+ zip (2.0.2)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ activesupport
45
+ autotest-fsevent (>= 0.2.2)
46
+ autotest-growl (>= 0.2.4)
47
+ builder
48
+ bundler (~> 1.0.0)
49
+ fastercsv
50
+ google-spreadsheet-ruby
51
+ jeweler (~> 1.5.0.pre3)
52
+ nokogiri
53
+ rcov
54
+ roo
55
+ rspec (>= 2.0.0.rc)
56
+ spreadsheet
57
+ zip
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright© Sprout Technology International Limited
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # Cloud Factory Validatior (CFValidator)
2
+
3
+ The CFInputValidator - Cloud Factory Input Validator is a simple gem to **validate** the *spreadsheet data* inputs as per the given rules.
4
+
5
+ This gem is being developed for Project **Cloud Factory** Copyright© [Sprout Technology International Limited](http://sprout-technology.com)
6
+
7
+ ![Sprout logo](http://sprout-technology.com/images/logo.png)
8
+
9
+ ## Installation
10
+
11
+ In Gemfile
12
+ source 'http://rubygems.org'
13
+ gem 'unit_validator'
14
+
15
+ bundle install
16
+
17
+ OR
18
+ gem install unit_validator
19
+
20
+ require 'rubygems'
21
+ require 'unit_validator'
22
+
23
+ ## Usage
24
+
25
+ The CFInputValidator checks if the **headers** of the provided spreadsheet matches with the corresponding **rules** *(checked by label)* and gives error message if it doesn't match.
26
+
27
+ The individual row of the spreadsheet undergoes the validation process and gives the final output as an array of **valid and invalid units**.
28
+ Later the valid and invalid units can be processed separately as required.
29
+
30
+ You can even check if a **file format** is supported by the gem.
31
+
32
+ The gem currently supports `validation_format` of `email`, `number`, `url`, `date` and `time` only.
33
+ It also checks if value is present if required is true.
34
+
35
+ ## Example
36
+
37
+ 1. Specify the rules, i.e `:label` `:required` `:validation_format`
38
+ rules = [{:label => "company name",:required => true, :validation_format => "general"},
39
+ {:label => "email", :required => false, :validation_format => "email"}]
40
+
41
+ 2. Provide data for validation:
42
+ inputs = "company name,email\nSprout,info@sproutify.com\nApple,saroj@apple"
43
+
44
+ **You can also give the file location as input**
45
+ inputs = File.read("fixtures/gdoc.csv")
46
+
47
+ * Check the file format with `check_extension(path)` method which gives you a 'boolean' value `:check`
48
+
49
+ `file_location = "fixtures/gdoc.xlsxsfdsf"`
50
+
51
+ `CFInputValidator.check_extension(file_location)[:check]`
52
+
53
+ * This gem currently supports the following formats and 'must be converted into csv' before validation.
54
+ * `inputs = File.read("fixtures/gdoc.csv")`
55
+ * `inputs = Excel.new("fixtures/gdoc.xls").to_csv`
56
+ * `inputs = Excelx.new("fixtures/gdoc.xlsx").to_csv`
57
+ * `inputs = Openoffice.new("fixtures/gdoc.ods").to_csv`
58
+
59
+ 3. Create a new constructor of *CF::InputValidator* class passing the above **rules** as argument.
60
+
61
+ cloud_validator = CF::InputValidator.new(rules)
62
+
63
+ 4. Call `parse_and_validate(data)` method passing the above inputs as arguments.
64
+ val = cloud_validator.parse_and_validate(inputs)
65
+
66
+ 5. Now you'll get both valid and invalid data in `:valid_units` and `:invalid_units` arrays respectively.
67
+ * `val[:valid_units]`
68
+ * `val[:invalid_units]`
69
+
70
+ 6. It will give a `.errors` instance variable as error if the *headers* of spreadsheet data doesn't match with the *rules* or vice-versa saying *"Headers doesnot match the column counts"*.
71
+ rules = [{:field_id => "field_1", :label => "company name", :field_type => "text_data",
72
+ :value => "Sprout", :required => true, :validation_format => "general"
73
+ }]
74
+ inputs = "company name,email\nSprout,info@sproutify.com"
75
+
76
+ cloud_validator = CF::InputValidator.new(rules)
77
+ val = cloud_validator.parse_and_validate(inputs)
78
+ err = val.errors
79
+
80
+
81
+ ## Note on Patches/Pull Requests
82
+
83
+ * Fork the project.
84
+ * Make your feature addition or bug fix.
85
+ * Add tests for it. This is important so I don't break it in a
86
+ future version unintentionally.
87
+ * Commit, do not mess with rakefile, version, or history.
88
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
89
+ * Send me a pull request. Bonus points for topic branches.
90
+
91
+ ### Copyright
92
+
93
+ Copyright© Sprout Technology International Limited. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,61 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "unit_validator"
16
+ gem.summary = %Q{Takes the Instruction Input as Rule, parse the CSV files and does the validation}
17
+ gem.description = %Q{Takes the Instruction Input as Rule, parse the CSV files and applies the validation and returns valid and invalid units}
18
+ gem.email = "saroj@sprout-technology.com"
19
+ gem.homepage = "http://github.com/sprout/unit_validator"
20
+ gem.authors = ["millisami", "zoras"]
21
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
22
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
23
+ gem.add_runtime_dependency 'roo'
24
+ gem.add_runtime_dependency 'zip'
25
+ gem.add_runtime_dependency 'spreadsheet'
26
+ gem.add_runtime_dependency 'nokogiri'
27
+ gem.add_runtime_dependency 'google-spreadsheet-ruby'
28
+ gem.add_runtime_dependency 'activesupport'
29
+ gem.add_runtime_dependency 'builder'
30
+
31
+ gem.add_development_dependency "rspec", ">= 2.0.0.rc"
32
+ gem.add_development_dependency "bundler", "~> 1.0.0"
33
+ gem.add_development_dependency "jeweler", "~> 1.5.0.pre3"
34
+ gem.add_development_dependency "rcov", ">= 0"
35
+ end
36
+ Jeweler::RubygemsDotOrgTasks.new
37
+
38
+ require 'rspec/core'
39
+ require 'rspec/core/rake_task'
40
+ # custom rcov
41
+ require File.expand_path(File.dirname(__FILE__) + '/lib/tasks/rcov_custom')
42
+ RSpec::Core::RakeTask.new(:spec) do |spec|
43
+ spec.pattern = FileList['spec/**/*_spec.rb']
44
+ end
45
+
46
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
47
+ spec.pattern = 'spec/**/*_spec.rb'
48
+ spec.rcov = true
49
+ end
50
+
51
+ task :default => :spec
52
+
53
+ require 'rake/rdoctask'
54
+ Rake::RDocTask.new do |rdoc|
55
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
56
+
57
+ rdoc.rdoc_dir = 'rdoc'
58
+ rdoc.title = "unit_validator #{version}"
59
+ rdoc.rdoc_files.include('README*')
60
+ rdoc.rdoc_files.include('lib/**/*.rb')
61
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,3 @@
1
+ Autotest.add_discovery do
2
+ "rspec2"
3
+ end
data/fixtures/gdoc.csv ADDED
@@ -0,0 +1,10 @@
1
+ company name,email
2
+ "Apple, Inc.",
3
+ Sprout,info@sproutify.com
4
+ ,inf o@ab c.com
5
+
6
+
7
+ DEF, info@def.com
8
+ GHI
9
+
10
+
data/fixtures/gdoc.ods ADDED
Binary file
data/fixtures/gdoc.xls ADDED
Binary file
Binary file
@@ -0,0 +1,72 @@
1
+ require 'fastercsv'
2
+ require 'roo'
3
+ require 'active_support/core_ext/object/blank'
4
+ require 'generic_spreadsheet'
5
+ require 'validator_helpers'
6
+
7
+ module CF
8
+ class InputValidator
9
+ include ValidatorHelpers
10
+
11
+ attr_accessor :errors, :rules
12
+
13
+ def initialize(rules)
14
+ @errors = []
15
+ @rules = rules
16
+ @invalid_units, @temp_units, @valid_units = [], [], []
17
+ end
18
+
19
+ def self.check_extension(file_location)
20
+ @error = []
21
+ ext = File.extname(file_location).sub(/./,"")
22
+ formats = %w[csv xls xlsx ods]
23
+ check = formats.include?(ext)
24
+
25
+ @error << "Invalid file! The specified format is not supported." unless check
26
+ {:check => check, :error => @error}
27
+ end
28
+
29
+ # returns a hash of arrays with two keys :valid_units and :invalid_units
30
+ # {:valid_units => @valid_units, :invalid_units => @invalid_units}
31
+ def parse_and_validate(inputs)
32
+ csv_contents = FasterCSV.parse(inputs)
33
+ csv_header = csv_contents[0].map{|a| a.strip unless a.nil? }
34
+
35
+ # Initialize rule_labels array and store labels of RULE_HEADERS into it
36
+ rule_labels = Array.new
37
+ rules.each do |rule|
38
+ rule_labels << rule[:label]
39
+ end
40
+
41
+ if rule_labels == csv_header
42
+ csv_contents[1..-1].each do |item|
43
+ # Validation.
44
+ rules.each_with_index do |header, index|
45
+ next unless item # Escape nil items. This may result while reading csv file with blank line
46
+
47
+ unless (item = item.select{|x| !x.blank? }).empty?
48
+ item[index].strip! if !item[index].nil?
49
+
50
+ if required(header[:required], item[index]) and valid(header[:validation_format], item[index])
51
+ # temporarily store valid units into temp_units array
52
+ @temp_units << item unless @temp_units.include?(item)
53
+ else
54
+ # Note:: While validating input data, collect invalid row(data) and process the others.
55
+ # Display invalid data to user later
56
+ @invalid_units << item unless @invalid_units.include?(item)
57
+ end
58
+ end
59
+ end
60
+
61
+ end
62
+ else
63
+ @errors << "Headers doesnot match the column counts"
64
+ end
65
+
66
+ # calculate valid_units
67
+ @valid_units = @temp_units - @invalid_units
68
+
69
+ {:valid_units => @valid_units, :invalid_units => @invalid_units}
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,52 @@
1
+ module CF
2
+ class ResultValidator
3
+ include ValidatorHelpers
4
+ attr_accessor :errors
5
+
6
+ def initialize
7
+ @errors = []
8
+ end
9
+
10
+ def valid?(rules, result)
11
+ csv_contents = FasterCSV.parse(result)
12
+ csv_header = csv_contents[0].map{|a| a.strip unless a.nil? }
13
+
14
+ rule_labels = Array.new
15
+ rules.each do |rule|
16
+ rule_labels << rule[:label]
17
+ end
18
+
19
+ bool = false
20
+ case (rule_labels <=> csv_header)
21
+ when 1
22
+ # when input header is less than rule label
23
+ @errors << "#{rule_labels - csv_header} is/are required"
24
+ when -1
25
+ # when input header is more than rule label
26
+ @errors << "cannot process as the input data consists extra headers"
27
+ when 0
28
+ # if rule_labels == csv_header
29
+ csv_contents[1..-1].each do |item|
30
+ rules.each_with_index do |header, index|
31
+ next unless item
32
+ unless item.compact.empty?
33
+ item[index].strip! if !item[index].nil?
34
+ if required(header[:required], item[index]) and valid(header[:validation_format], item[index])
35
+ bool = true
36
+ else
37
+ bool = false
38
+ if header[:required] && item[index].blank?
39
+ @errors << "#{header[:label]} is required"
40
+ else
41
+ @errors << "#{item[index]} is not valid"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ # finally return boolean for .valid?
49
+ return bool
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,23 @@
1
+ class GenericSpreadsheet
2
+
3
+ # write the current spreadsheet to csv_string
4
+ def to_csv(filename=nil,sheet=nil)
5
+ csv_string = write_csv_content(STDOUT,sheet)
6
+ end
7
+
8
+ def write_csv_content(file=nil,sheet=nil)
9
+ csv_string = ""
10
+ if first_row(sheet) # sheet is not empty
11
+ 1.upto(last_row(sheet)) do |row|
12
+ 1.upto(last_column(sheet)) do |col|
13
+ csv_string += "," if col > 1
14
+ onecell = cell(row,col,sheet)
15
+ onecelltype = celltype(row,col,sheet)
16
+ csv_string += one_cell_output(onecelltype,onecell,empty?(row,col,sheet))
17
+ end
18
+ csv_string += "\n"
19
+ end # sheet not empty
20
+ end
21
+ csv_string
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ desc "Custom rcov"
2
+ RSpec::Core::RakeTask.new(:rcov_custom) do |t|
3
+ t.rcov = true
4
+ t.rcov_opts = %w{--exclude gems\/,spec\/ -T}
5
+ end
@@ -0,0 +1,56 @@
1
+ module ValidatorHelpers
2
+
3
+ private
4
+
5
+ def required(rule, value)
6
+ # returns true unless value is blank when required rule is true
7
+ (rule && value.blank?) ? false : true
8
+ end
9
+
10
+ def valid(format, value)
11
+ case format
12
+ when "email"
13
+ regex = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
14
+ when "url" # image_data => url, path
15
+ regex = /^(http:\/\/|https:\/\/)?(www.)?[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3})([.]?[a-zA-Z]{2})?(\/\S*)?$/i
16
+ msg = "Start with http:// or https://"
17
+ when "number"
18
+ regex = /^\d{1,3}(\,?\d{3})*$/
19
+ when "date"
20
+ # Check if date (dd.mm.yyyy) is valid date or not
21
+ #regex = /\d{1,2}(\/|-|\.|\s)\d{1,2}(\/|-|\.|\s)\d{2,4}/
22
+ test = check_date(value)
23
+ return test
24
+ when "time"
25
+ regex = /^(([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(:([0-5]?[0-9]))?$/
26
+ when "datetime"
27
+ regex = /^(1[0-2]|0?[1-9])\/(3[01]|[12][0-9]|0?[1-9])\/(?:[0-9]{2})?[0-9]{2}|(([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(:([0-5]?[0-9]))?$/
28
+ when "currency" #=> for USD
29
+ regex = /^\$?(?:\d+|\d{1,3}(?:,\d{3})*)(?:\.\d{1,2}){0,1}$/
30
+ # when "boolean"
31
+ # when "rating"
32
+ # when "radio"
33
+ # when "checkbox" => multiple choice
34
+ when "general"
35
+ return true
36
+ else
37
+ @errors << "Validation format not supported:: #{format}"
38
+ # puts "error message:: #{@errors.inspect}"
39
+ return false
40
+ end
41
+
42
+ if !value.blank?
43
+ !value.match(regex).nil? ? true : false
44
+ end
45
+ end
46
+
47
+ def check_date(value)
48
+ begin
49
+ val = value.scan(/^(\d{1,2})[\/|-|\.|\s](\d{1,2})[\/|-|\.|\s](\d{2,4})$/) # dd.mm.yyyy
50
+ Date.civil(val[0][2].to_i,val[0][1].to_i,val[0][0].to_i) # civil check julian date in yyyy.mm.dd
51
+ !val.blank? ? true : false
52
+ rescue
53
+ return false
54
+ end
55
+ end
56
+ end
data/spec/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color