cardia 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.
@@ -0,0 +1,189 @@
1
+ require 'time'
2
+ require 'validateable'
3
+
4
+ module ActiveMerchant
5
+ module Billing
6
+
7
+ # Represents a credit card
8
+ class CreditCard
9
+ include Validateable
10
+
11
+ attr_accessor :number, :month, :year, :first_name, :last_name, :type
12
+
13
+ # Creates a new Credit card instance
14
+ # Valid options are
15
+ # * :number
16
+ # * :month
17
+ # * :year
18
+ # * :first_name
19
+ # * :last_name
20
+ # * :verification_value
21
+ # * :type
22
+ def initialize(options = {})
23
+ options.each do |key, value|
24
+ self.send("#{key}=", value)
25
+ end
26
+ end
27
+
28
+ # Optional verification_value (CVV, CVV2 etc)
29
+ attr_accessor :verification_value
30
+
31
+ def to_param #:nodoc:
32
+ return {
33
+ :number => self.number,
34
+ :month => self.month,
35
+ :year => self.year,
36
+ :type => self.type,
37
+ :first_name => self.first_name,
38
+ :last_name => self.last_name,
39
+ :verification_value => self.verification_value}
40
+ end
41
+
42
+ # Returns a valid credit card (visa) for testing purposes.
43
+ def self.valid_card_for_testing
44
+ result = self.new
45
+ result.number = "4569971388844836"
46
+ result.verification_value = "081"
47
+ result.expiry_date = Date.parse("2017-03-01")
48
+ result.type = "visa"
49
+ result.first_name = "John"
50
+ result.last_name = "Doe"
51
+ return result
52
+ end
53
+
54
+ # Returns an invalid credit card for testing purposes
55
+ def self.invalid_card_for_testing
56
+ result = self.valid_card_for_testing
57
+ result.number = "45699713888448360"
58
+ return result
59
+ end
60
+
61
+ def before_validate #:nodoc:
62
+ self.type.downcase! if type.respond_to?(:downcase)
63
+ self.month = month.to_i
64
+ self.year = year.to_i
65
+ self.number.to_s.gsub!(/[^\d]/, "")
66
+ end
67
+
68
+ def validate #:nodoc:
69
+ @errors.add "year", "expired" if expired?
70
+ #@errors.add "first_name", "cannot be empty" unless @first_name
71
+ #@errors.add "last_name", "cannot be empty" unless @last_name
72
+ @errors.add "month", "cannot be empty" unless (1..12).include?(month.to_i)
73
+ @errors.add "year", "cannot be empty" unless (Time.now.year..Time.now.year+10).include?(year.to_i)
74
+
75
+ # Bogus card is pretty much for testing purposes. Lets just skip these extra tests if its used
76
+ return if type == 'bogus'
77
+
78
+ @errors.add "number", "is not a vaild credit card number" unless CreditCard.valid_number?(number)
79
+ @errors.add "type", "is invalid." unless CreditCard.card_companies.include?(type)
80
+ @errors.add "type", "is not the correct card type" unless CreditCard.type?(number) == type
81
+ end
82
+
83
+ # Expiry date in mmyy format
84
+ def expires
85
+ expiry_date.strftime("%m%y")
86
+ end
87
+
88
+ # Sets the expiry date, takes a Date instance
89
+ def expiry_date=(a_date)
90
+ self.year = a_date.year
91
+ self.month = a_date.month
92
+ end
93
+
94
+ def expiry_date #:nodoc:
95
+ Date.parse("#{year}-#{month}-01")
96
+ end
97
+
98
+ def expired? #:nodoc:
99
+ Time.now > Time.parse("#{month}/28/#{year}") rescue true
100
+ end
101
+
102
+ def name? #:nodoc:
103
+ @first_name != nil and @last_name != nil
104
+ end
105
+
106
+ def first_name? #:nodoc:
107
+ @first_name != nil
108
+ end
109
+
110
+ def last_name? #:nodoc:
111
+ @last_name != nil
112
+ end
113
+
114
+ def name #:nodoc:
115
+ "#{@first_name} #{@last_name}"
116
+ end
117
+
118
+ def payment_type
119
+ "1000"
120
+ end
121
+
122
+ def verification_value? #:nodoc:
123
+ @verification_value != nil
124
+ end
125
+
126
+ # Get the regexps for different card companies
127
+ # == Known card types
128
+ # *Card Type* *Prefix* *Length*
129
+ # mastercard 51-55 16
130
+ # visa 4 13, 16
131
+ # american_express 34, 37 15
132
+ # diners_club 300-305, 36, 38 14
133
+ # enroute 2014, 2149 15
134
+ # discover 6011 16
135
+ # jcb 3 16
136
+ # jcb 2131, 1800 15
137
+ # bankcard 5610, 56022[1-5] 16
138
+ # switch various 16,18,19
139
+ # solo 63, 6767 16,18,19
140
+ def self.card_companies_to_pattern #:nodoc:
141
+ {
142
+ 'visa' => /^4\d{12}(\d{3})?$/,
143
+ 'master' => /^5[1-5]\d{14}$/,
144
+ 'discover' => /^6011\d{12}$/,
145
+ 'american_express' => /^3[47]\d{13}$/,
146
+ 'diners_club' => /^3(0[0-5]|[68]\d)\d{11}$/,
147
+ 'enroute' => /^2(014|149)\d{11}$/,
148
+ 'jcb' => /^(3\d{4}|2131|1800)\d{11}$/,
149
+ 'bankcard' => /^56(10\d\d|022[1-5])\d{10}$/,
150
+ 'switch' => [/^49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})\d{10}(\d{2,3})?$/, /^564182\d{10}(\d{2,3})?$/, /^6(3(33[0-4][0-9])|759[0-9]{2})\d{10}(\d{2,3})?$/],
151
+ 'solo' => /^6(3(34[5-9][0-9])|767[0-9]{2})\d{10}(\d{2,3})?$/
152
+ }
153
+ end
154
+
155
+ def self.card_companies #:nodoc:
156
+ return card_companies_to_pattern.keys
157
+ end
158
+
159
+ # Returns a string containing the type of card from the list of known information below.
160
+ def self.type?(number) #:nodoc:
161
+ card_companies_to_pattern.each do |company, patterns|
162
+ return company if [patterns].flatten.any? { |pattern| number =~ pattern }
163
+ end
164
+ end
165
+
166
+ # Returns true if it validates. Optionally, you can pass a card type as an argument and make sure it is of the correct type.
167
+ # == References
168
+ # - http://perl.about.com/compute/perl/library/nosearch/P073000.htm
169
+ # - http://www.beachnet.com/~hstiles/cardtype.html
170
+ def self.valid_number?(number)
171
+ return false unless number.to_s.length >= 13
172
+
173
+ sum = 0
174
+ for i in 0..number.length
175
+ weight = number[-1 * (i + 2), 1].to_i * (2 - (i % 2))
176
+ sum += (weight < 10) ? weight : weight - 9
177
+ end
178
+
179
+ (number[-1,1].to_i == (10 - sum % 10) % 10)
180
+ end
181
+
182
+ # Show the card number, with all but last 4 numbers replace with "x". (xxxxxxxxxxxx-4338)
183
+ def display_number
184
+ return @number if @number.blank? || @number.length < 5
185
+ "#{'x' * (@number.length - 4)}-#{@number[-4, 4]}"
186
+ end
187
+ end
188
+ end
189
+ end
data/lib/enum.rb ADDED
@@ -0,0 +1,78 @@
1
+ # Provides simple enumerability to classes
2
+ class Object #:nodoc:
3
+
4
+ # The hidden singleton lurks behind everyone
5
+ def metaclass; class << self; self; end; end
6
+ def meta_eval(&blk); metaclass.instance_eval &blk; end
7
+
8
+ # Adds methods to a metaclass
9
+ def meta_def name, &blk
10
+ meta_eval { define_method name, &blk }
11
+ end
12
+
13
+ # Defines an instance method within a class
14
+ def class_def name, &blk
15
+ class_eval { define_method name, &blk }
16
+ end
17
+ end
18
+
19
+ class Enum #:nodoc:
20
+ attr_reader :code
21
+
22
+ def initialize(a_code)
23
+ @code = a_code.to_i unless a_code.nil?
24
+ end
25
+
26
+ def ==(an_object)
27
+ self.class == an_object.class and self.code == an_object.code
28
+ end
29
+
30
+ def self.enums
31
+ @enums ||= {}
32
+ end
33
+
34
+ # Adds a new enum code.
35
+ # If description isn't provided, name is used instead
36
+ def self.map(name, a_code, description=nil)
37
+ enum_description = (description || name.to_s)
38
+ self.enums[a_code] = enum_description
39
+ self.define_constructor(name, a_code)
40
+ define_method "#{name}?" do
41
+ return @code == a_code
42
+ end
43
+ end
44
+
45
+ def self.define_constructor(name, a_code)
46
+ meta_def(name.to_sym) do
47
+ return self.new(a_code)
48
+ end
49
+ end
50
+
51
+ def to_s
52
+ description
53
+ end
54
+
55
+ def description
56
+ self.class.enums[@code]
57
+ end
58
+ end
59
+
60
+
61
+ module Enumerable #:nodoc:
62
+ class Mapper #:nodoc:
63
+ def initialize( collection )
64
+ @collection = collection
65
+ end
66
+ def method_missing( meth_id, *args)
67
+ @collection.map{ |a| a.send(meth_id, *args) }
68
+ end
69
+ end
70
+
71
+ def mapped
72
+ Mapper.new( self )
73
+ end
74
+
75
+ alias :collected :mapped
76
+
77
+ end
78
+
@@ -0,0 +1,80 @@
1
+ module ActiveMerchant #:nodoc:
2
+
3
+ # Implements the standard ActiveRecord stuff for non-AR classes
4
+ module Validateable #:nodoc:
5
+ def valid?
6
+ errors.clear
7
+
8
+ before_validate if respond_to?(:before_validate)
9
+ validate if respond_to?(:validate)
10
+
11
+ errors.empty?
12
+ end
13
+
14
+ def initialize(attributes = {})
15
+ self.attributes = attributes
16
+ end
17
+
18
+ def errors
19
+ @errors ||= Error.new(self)
20
+ end
21
+
22
+ private
23
+
24
+ def attributes=(attributes)
25
+ unless attributes.nil?
26
+ for key, value in attributes
27
+ send("#{key}=", value )
28
+ end
29
+ end
30
+ end
31
+
32
+ # This hash keeps the errors of the object
33
+ class Error < Hash #:nodoc:
34
+
35
+ def initialize(base)
36
+ @base = base
37
+ end
38
+
39
+ def count
40
+ size
41
+ end
42
+
43
+ # returns a specific fields error message.
44
+ # if more than one error is available we will only return the first. If no error is available
45
+ # we return an empty string
46
+ def on(field)
47
+ self[field].to_a.first
48
+ end
49
+
50
+ def add(field, error)
51
+ self[field] ||= []
52
+ self[field] << error
53
+ end
54
+
55
+ def add_to_base(error)
56
+ add(:base, error)
57
+ end
58
+
59
+ def each_full
60
+ full_messages.each { |msg| yield msg }
61
+ end
62
+
63
+ def full_messages
64
+ result = []
65
+
66
+ self.each do |key, messages|
67
+ if key == :base
68
+ result << "#{messages.first}"
69
+ else
70
+ result << "#{key.to_s.humanize} #{messages.first}"
71
+ end
72
+ end
73
+
74
+ result
75
+ end
76
+ end
77
+ end
78
+
79
+
80
+ end
data/log/debug.log ADDED
File without changes
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)