hash_params 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.
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: