hash_params 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +37 -0
  4. data/LICENSE +19 -0
  5. data/README.md +174 -0
  6. data/Rakefile +11 -0
  7. data/coverage/assets/0.8.0/application.css +799 -0
  8. data/coverage/assets/0.8.0/application.js +1559 -0
  9. data/coverage/assets/0.8.0/colorbox/border.png +0 -0
  10. data/coverage/assets/0.8.0/colorbox/controls.png +0 -0
  11. data/coverage/assets/0.8.0/colorbox/loading.gif +0 -0
  12. data/coverage/assets/0.8.0/colorbox/loading_background.png +0 -0
  13. data/coverage/assets/0.8.0/favicon_green.png +0 -0
  14. data/coverage/assets/0.8.0/favicon_red.png +0 -0
  15. data/coverage/assets/0.8.0/favicon_yellow.png +0 -0
  16. data/coverage/assets/0.8.0/loading.gif +0 -0
  17. data/coverage/assets/0.8.0/magnify.png +0 -0
  18. data/coverage/assets/0.8.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  19. data/coverage/assets/0.8.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  20. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  21. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  22. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  23. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  24. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  25. data/coverage/assets/0.8.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  26. data/coverage/assets/0.8.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  27. data/coverage/assets/0.8.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  28. data/coverage/assets/0.8.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  29. data/coverage/assets/0.8.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  30. data/coverage/assets/0.8.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  31. data/coverage/index.html +964 -0
  32. data/hash_params.gemspec +27 -0
  33. data/lib/hash_params.rb +157 -0
  34. data/spec/hash_params_spec.rb +86 -0
  35. data/spec/spec_helper.rb +24 -0
  36. metadata +152 -0
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/hash_params', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'hash_params'
6
+ s.license = 'MIT'
7
+ s.authors = ['Tim Uckun']
8
+ s.email = 'tim@uckun.com'
9
+ s.homepage = 'https://github.com/timuckun/hash_params'
10
+ s.version = HashParams::VERSION
11
+ s.platform = Gem::Platform::RUBY
12
+ s.summary = 'Parameter Validation & Type Coercion for parameters passed in as a Hash..'
13
+ s.description = 'hash-param allows you to declare, validate, and transform endpoint parameters as you would in frameworks like ActiveModel or DataMapper without the overhead.
14
+ This gem is a variation of the sinatra-param gem https://github.com/mattt/sinatra-param modified to be more generic and with some additional features'
15
+
16
+
17
+ s.add_development_dependency 'rake'
18
+ s.add_development_dependency 'minitest'
19
+ s.add_development_dependency 'minitest-spec'
20
+ s.add_development_dependency 'simplecov'
21
+ s.add_development_dependency 'pry'
22
+
23
+ s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor)/ }
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
@@ -0,0 +1,157 @@
1
+ class HashParams < Hash
2
+ VERSION = '0.0.1'
3
+ attr :valid, :errors
4
+
5
+ def self.ping
6
+ 'ping'
7
+ end
8
+ def initialize(opts={}, injection_target =nil, &code)
9
+ @incoming_hash = opts
10
+ @errors =[]
11
+ # @parent = code.binding.eval 'self'
12
+ @target =injection_target
13
+ instance_eval(&code)
14
+ @valid = (@errors.size == 0)
15
+ end
16
+
17
+ def param(key, h = {})
18
+
19
+
20
+
21
+
22
+
23
+ #What happens if value is FalseClass ? Need something a little better
24
+ val = @incoming_hash[key] || @incoming_hash[key.to_sym] || @incoming_hash[key.to_s]
25
+ if val.nil? && h[:default]
26
+ val = h[:default].respond_to?(:call) ? h[:default].call(self) : h[:default]
27
+ end
28
+
29
+ #don't bother with the rest if required parameter is missing
30
+ return @errors << "Parameter #{key} is required and missing" if h[:required] && val.nil?
31
+ #do all coercion and transformation first there could be an array of coersions they will be run in order
32
+
33
+ Array(h[:coerce]).each do |c|
34
+ val = coerce(val, c, h)
35
+ end
36
+
37
+
38
+ #coersion could return a nil which won't validate, it could return a false which will attempt to validate
39
+ if validate!(val, h)
40
+ #The value is valid add it
41
+ var_name = h[:as] ? h[:as] : key
42
+ self[var_name]=val
43
+ inject_into_target(@target, var_name, val)
44
+ end
45
+
46
+ #after all that see if a block is given and process that
47
+ if block_given? && val.is_a?(Hash)
48
+ #Proc.new references the implict block
49
+ val = HashParams.new(val, nil, &Proc.new)
50
+ end
51
+
52
+ val
53
+ rescue => e
54
+ @errors << e.to_s
55
+ end
56
+
57
+ def inject_into_target(target, var_name, val)
58
+ if target
59
+ #for read write methods
60
+ target.singleton_class.class_eval do
61
+ attr_accessor var_name;
62
+ end
63
+ target.send("#{var_name}=", val)
64
+ end
65
+ end
66
+
67
+ def validate!(param, options ={})
68
+ return false if param.nil?
69
+ is_valid = true
70
+
71
+ options.each do |key, value|
72
+
73
+ error = case key
74
+ when :validate
75
+ "#{param.to_s} failed validation using proc" if value.respond_to?(:call) && !value.call(param)
76
+ when :blank
77
+ 'Parameter cannot be blank' if !value && blank?(param)
78
+ when :format
79
+ 'Parameter must be a string if using the format validation' && next unless param.kind_of?(String)
80
+ "Parameter must match format #{value}" unless param =~ value
81
+ when :is
82
+ "Parameter must be #{value}" unless param === value
83
+ when :in, :within, :range
84
+ "Parameter must be within #{value}" unless value.respond_to?(:include) ? value.include?(param) : Array(value).include?(param)
85
+ when :min
86
+ "Parameter cannot be less than #{value}" unless value <= param
87
+ when :max
88
+ "Parameter cannot be greater than #{value}" unless value >= param
89
+ when :min_length
90
+ "Parameter cannot have length less than #{value}" unless value <= param.length
91
+ when :max_length
92
+ "Parameter cannot have length greater than #{value}" unless value >= param.length
93
+ else
94
+ nil
95
+ end
96
+ if error
97
+ @errors << error
98
+ is_valid = false
99
+ end
100
+ end
101
+
102
+ #return true or false depending on if it validated
103
+ is_valid
104
+ end
105
+
106
+
107
+ def coerce(val, type, h)
108
+
109
+ # exceptions bubble up
110
+ #order is important
111
+ return val if type.nil? || val.nil?
112
+
113
+ #two special types of transforms
114
+ #There is no Boolean type so we handle them special
115
+ if type == :boolean || type =='boolean'
116
+ return val if (val == true || val == false)
117
+ return false if /(false|f|no|n|0)$/i === val.to_s.downcase
118
+ return true if /(true|t|yes|y|1)$/i === val.to_s.downcase
119
+
120
+ # if we can't parse we return a nil
121
+ # maybe !!val is a better return?
122
+ return nil
123
+ end
124
+ #they have given us a coercion which is a string or symbol which is not "boolean", we are going to cast this into a proc and run it
125
+
126
+ return type.to_proc.call(val) if type.is_a?(Symbol) || type.is_a?(String)
127
+ #could be a proc
128
+
129
+ return type.call(val) if type.respond_to?(:call)
130
+ #nothing but simple types left
131
+ return val if val.is_a?(type)
132
+ return Integer(val) if type == Integer
133
+ return Float(val) if type == Float
134
+ return String(val) if type == String
135
+ return Date.parse(val) if type == Date
136
+ return Time.parse(val) if type == Time
137
+ return DateTime.parse(val) if type == DateTime
138
+ return Array(val.split(h[:delimiter] || ',')) if type == Array
139
+ return Hash[val.gsub(/[{}]/,'').gsub('}','').split(h[:delimiter] || ',').map { |c| c.split(h[:separator] ||':').map{|i| i.strip} }] if type == Hash
140
+
141
+ nil
142
+ end
143
+
144
+ def valid?
145
+ @valid
146
+ end
147
+ def present?(object)
148
+ !blank?(object)
149
+ end
150
+
151
+ def blank?(object)
152
+ return true if object.nil?
153
+ return true if object.respond_to?(:empty) && object.empty
154
+ return false
155
+ end
156
+
157
+ end
@@ -0,0 +1,86 @@
1
+ require_relative 'spec_helper'
2
+
3
+
4
+ describe HashParams do
5
+
6
+ let (:r) {
7
+ HashParams.new(
8
+ {
9
+ ignored: "this will be ignored because it's not mentioned",
10
+ to_be_renamed: :to_be_renamed,
11
+ integer_coercion: "1",
12
+ bad_number: '1aaa2',
13
+ array_with_delim: '1|2|3',
14
+ hash_as_string: "{a => 1,b => 2,c => d}",
15
+ proc_validation: "is_this_valid?",
16
+ some_number: 122,
17
+ some_string: 'this is a test string' ,
18
+ is_true: 'true',
19
+ is_false: 'f',
20
+ recursive: {}
21
+ }
22
+ ) do
23
+ param :doesnt_exist, required: true
24
+ param :to_be_renamed, as: :renamed
25
+ param :no_value, default: 1
26
+ #proc default relying on previously set value
27
+ param :proc_default, default: lambda { |o| o[:no_value] * 5 }
28
+ param :integer_coercion, coerce: Integer
29
+ #chained coersions of various types
30
+ param :bad_number, coerce: [lambda { |o| o.gsub('a', '') }, :to_i, Float]
31
+ #arrays and hashes
32
+ param :array_with_delim, coerce: Array, delimiter: '|'
33
+ param :hash_as_string, coerce: Hash, delimiter: ',', separator: '=>'
34
+ param :proc_validation, validate: lambda { |v| v == 'Failed_proc_validation' }
35
+ #validations
36
+ param :some_number, min: 120, max: 500, in: (100..200), is: 122
37
+ param :some_string, min_length: 21, max_length: 30, format: /^t.*g$/
38
+ #combinations
39
+ param :missing_with_validation, coerce: Integer, :default => 60 * 60, :validate => lambda { |v| v >= 60 * 60 }
40
+ param :is_true, coerce: :boolean
41
+ param :is_false, coerce: :boolean
42
+ #recursive
43
+ param :recursive do
44
+ param :wasnt_here_before, default: true
45
+ end
46
+ end
47
+ }
48
+
49
+
50
+ it 'does amazing things' do
51
+ (r.valid?).must_equal false
52
+ r[:ignored].must_be_nil
53
+ r[:no_value].must_equal 1
54
+ r[:proc_default].must_equal 5
55
+ r[:renamed].must_equal :to_be_renamed
56
+ r[:integer_coercion].must_equal 1
57
+ r[:bad_number].must_equal 12.0
58
+
59
+ r[:array_with_delim].must_equal ["1", "2", "3"]
60
+ r[:hash_as_string].must_equal ({ "a" => "1", "b" => "2", "c" => "d" })
61
+ r[:missing_with_validation].must_equal 60 * 60
62
+ r[:is_true].must_equal true
63
+ r[:is_false].must_equal false
64
+
65
+ #recursive checking
66
+ r[:recursive][:wasnt_here_before].must_equal true
67
+
68
+ #failed items don't show up
69
+ r.errors.size.must_equal 2
70
+ r[:doesnt_exist].must_be_nil
71
+ r[:proc_validation].must_be_nil
72
+ r.errors[0].must_equal 'Parameter doesnt_exist is required and missing'
73
+ r.errors[1].must_equal 'is_this_valid? failed validation using proc'
74
+
75
+ end
76
+
77
+ it 'injects into current class' do
78
+ r = HashParams.new({will_be_injected: 12345}, self) do
79
+ param :will_be_injected
80
+ end
81
+ r[:will_be_injected].must_equal 12345
82
+ @will_be_injected.must_equal 12345
83
+ will_be_injected.must_equal 12345
84
+ end
85
+
86
+ end
@@ -0,0 +1,24 @@
1
+ unless ENV['CI']
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter 'spec'
5
+ add_filter '.bundle'
6
+ end
7
+ end
8
+
9
+ require_relative '../lib/hash_params'
10
+ require 'minitest/spec'
11
+ require 'minitest/autorun'
12
+ require 'pry'
13
+
14
+ #require 'minitest/mock'
15
+
16
+ # require 'rack/test'
17
+ #
18
+ # require 'dummy/app'
19
+ #
20
+ # def app
21
+ # App
22
+ # end
23
+ #
24
+ # #include Rack::Test::Methods
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hash_params
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tim Uckun
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-spec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: |-
84
+ hash-param allows you to declare, validate, and transform endpoint parameters as you would in frameworks like ActiveModel or DataMapper without the overhead.
85
+ This gem is a variation of the sinatra-param gem https://github.com/mattt/sinatra-param modified to be more generic and with some additional features
86
+ email: tim@uckun.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - "./Gemfile"
92
+ - "./Gemfile.lock"
93
+ - "./LICENSE"
94
+ - "./README.md"
95
+ - "./Rakefile"
96
+ - "./coverage/assets/0.8.0/application.css"
97
+ - "./coverage/assets/0.8.0/application.js"
98
+ - "./coverage/assets/0.8.0/colorbox/border.png"
99
+ - "./coverage/assets/0.8.0/colorbox/controls.png"
100
+ - "./coverage/assets/0.8.0/colorbox/loading.gif"
101
+ - "./coverage/assets/0.8.0/colorbox/loading_background.png"
102
+ - "./coverage/assets/0.8.0/favicon_green.png"
103
+ - "./coverage/assets/0.8.0/favicon_red.png"
104
+ - "./coverage/assets/0.8.0/favicon_yellow.png"
105
+ - "./coverage/assets/0.8.0/loading.gif"
106
+ - "./coverage/assets/0.8.0/magnify.png"
107
+ - "./coverage/assets/0.8.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png"
108
+ - "./coverage/assets/0.8.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png"
109
+ - "./coverage/assets/0.8.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png"
110
+ - "./coverage/assets/0.8.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png"
111
+ - "./coverage/assets/0.8.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png"
112
+ - "./coverage/assets/0.8.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png"
113
+ - "./coverage/assets/0.8.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png"
114
+ - "./coverage/assets/0.8.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png"
115
+ - "./coverage/assets/0.8.0/smoothness/images/ui-icons_222222_256x240.png"
116
+ - "./coverage/assets/0.8.0/smoothness/images/ui-icons_2e83ff_256x240.png"
117
+ - "./coverage/assets/0.8.0/smoothness/images/ui-icons_454545_256x240.png"
118
+ - "./coverage/assets/0.8.0/smoothness/images/ui-icons_888888_256x240.png"
119
+ - "./coverage/assets/0.8.0/smoothness/images/ui-icons_cd0a0a_256x240.png"
120
+ - "./coverage/index.html"
121
+ - "./hash_params.gemspec"
122
+ - "./lib/hash_params.rb"
123
+ - spec/hash_params_spec.rb
124
+ - spec/spec_helper.rb
125
+ homepage: https://github.com/timuckun/hash_params
126
+ licenses:
127
+ - MIT
128
+ metadata: {}
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project:
145
+ rubygems_version: 2.2.2
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: Parameter Validation & Type Coercion for parameters passed in as a Hash..
149
+ test_files:
150
+ - spec/hash_params_spec.rb
151
+ - spec/spec_helper.rb
152
+ has_rdoc: