nashie 0.0.3 → 0.0.5
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.
- data/Gemfile +1 -0
- data/README.md +43 -8
- data/lib/nash/version.rb +1 -1
- data/lib/nashie.rb +54 -20
- data/nashie.gemspec +1 -1
- data/spec/nashie_spec.rb +92 -0
- metadata +64 -68
- data/spec/nash_spec.rb +0 -49
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Nashie
|
2
|
-
|
3
|
-
|
2
|
+
|
3
|
+
Nashie takes the Hashie concept one step further and allows you to create nested structure with buildin validation logic.
|
4
|
+
|
5
|
+
Nashies are used in the wild as presenters for API responses and to validate incoming API calls.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -18,16 +20,49 @@ Or install it yourself as:
|
|
18
20
|
|
19
21
|
## Usage
|
20
22
|
|
23
|
+
class Part < Hashie::Nash
|
24
|
+
property :name, :required => true
|
25
|
+
end
|
26
|
+
|
27
|
+
class Engine < Hashie::Nash
|
28
|
+
property :build_year, :required => true
|
29
|
+
property :nitro, :default => false
|
30
|
+
property :parts, :collection => true, :class => "Part"
|
31
|
+
end
|
32
|
+
|
21
33
|
class Car < Hashie::Nash
|
22
|
-
class Engine
|
23
|
-
|
24
|
-
|
34
|
+
property :engine, :required => true, :class => Engine
|
35
|
+
end
|
36
|
+
|
37
|
+
car = Car.new "engine" => {"build_year" => 2010, "nitro" => false, :parts => [{"name" => "crankshaft"}, {"name" => "flywheel"}]}
|
38
|
+
## Overrides
|
39
|
+
|
40
|
+
It's possible that you have custom validation logic that is not covered by nashies.
|
41
|
+
Internally nashies use the "new" class method which can be overridden if needed.
|
42
|
+
|
43
|
+
class Motorcycle
|
44
|
+
def self.new hash
|
45
|
+
raise "Euhm, a motorcycle has 2 wheels you know..." if not hash[:wheels].eql? 2
|
46
|
+
super hash
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
## DSL
|
51
|
+
|
52
|
+
A DSL is created that acts similar, it works by autocreating the classes as illustrated above (namespaced to the parent class).
|
53
|
+
The example below for example will convert the block to a Presentation::Users class with similar properties.
|
54
|
+
The block body passed to the property is executed on the class-level so you can define methods and override methods if needed.
|
55
|
+
|
56
|
+
class Presentation < Hashie::Nash
|
57
|
+
property :users, :collection => true, :required => true do
|
58
|
+
property :name
|
25
59
|
end
|
26
|
-
|
27
|
-
property :engine, :required => true, :class => Engine
|
28
60
|
end
|
29
61
|
|
30
|
-
|
62
|
+
## Future work
|
63
|
+
|
64
|
+
- more types of validations
|
65
|
+
- Customizable error messages
|
31
66
|
|
32
67
|
## Contributing
|
33
68
|
|
data/lib/nash/version.rb
CHANGED
data/lib/nashie.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
require "nash/version"
|
2
|
-
require 'hashie/
|
2
|
+
require 'hashie/trash'
|
3
3
|
require 'set'
|
4
4
|
|
5
5
|
module Hashie
|
6
6
|
# A Nash is a Nested Defined Hash and is an extension of a Dash
|
7
|
-
# A Nash allows you to create complex assignments composing of
|
7
|
+
# A Nash allows you to create complex assignments composing of
|
8
8
|
# several nested Dashes
|
9
|
-
#
|
10
9
|
#
|
11
|
-
#
|
10
|
+
#
|
11
|
+
# Nashes are useful when you need to create a lightweigth nested
|
12
12
|
# data object, ideal for validating JSON
|
13
|
-
class Nash < Hashie::
|
13
|
+
class Nash < Hashie::Trash
|
14
14
|
include Hashie::PrettyInspect
|
15
15
|
alias_method :to_s, :inspect
|
16
16
|
|
@@ -34,7 +34,14 @@ module Hashie
|
|
34
34
|
# should be instantiated when an assignment is made to this
|
35
35
|
# property.
|
36
36
|
#
|
37
|
-
def self.property(property_name, options = {})
|
37
|
+
def self.property(property_name, options = {}, &block)
|
38
|
+
if block_given?
|
39
|
+
# if my college professor sees this he will personally come and beat the shit out of me :(
|
40
|
+
class_name = property_name.to_s.capitalize
|
41
|
+
class_ref = const_set(class_name, Class.new(Hashie::Nash))
|
42
|
+
class_ref.class_eval &block
|
43
|
+
options[:class] = class_name
|
44
|
+
end
|
38
45
|
property_name = property_name.to_sym
|
39
46
|
|
40
47
|
self.properties << property_name
|
@@ -42,18 +49,45 @@ module Hashie
|
|
42
49
|
if options.has_key?(:class)
|
43
50
|
class_name = options[:class].to_s
|
44
51
|
class_properties[property_name] = class_name if options.delete(:class)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
52
|
+
if not options[:collection]
|
53
|
+
class_eval <<-ACCESSORS
|
54
|
+
def #{property_name}(&block)
|
55
|
+
self.[](#{property_name.to_s.inspect}, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
def #{property_name}=(value)
|
59
|
+
self.[]=(#{property_name.to_s.inspect}, #{class_properties[property_name]}.new(value))
|
60
|
+
end
|
61
|
+
|
62
|
+
ACCESSORS
|
63
|
+
else
|
64
|
+
# expect arrays and convert single items into arrays
|
65
|
+
class_eval <<-ACCESSORS
|
66
|
+
def #{property_name}(&block)
|
67
|
+
self.[](#{property_name.to_s.inspect}, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
def #{property_name}=(value)
|
71
|
+
if not value.is_a? Array
|
72
|
+
if #{options[:permissive]}
|
73
|
+
value = [value]
|
74
|
+
else
|
75
|
+
raise "#{property_name} requires an array, use :permissive => true to automatically convert to array"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
values = []
|
79
|
+
value.each do |item|
|
80
|
+
values << #{class_properties[property_name]}.new(item)
|
81
|
+
end
|
82
|
+
values =
|
83
|
+
self.[]=(#{property_name.to_s.inspect}, values)
|
84
|
+
end
|
85
|
+
|
86
|
+
ACCESSORS
|
87
|
+
|
88
|
+
end
|
89
|
+
|
49
90
|
|
50
|
-
def #{property_name}=(value)
|
51
|
-
self.[]=(#{property_name.to_s.inspect}, #{class_properties[property_name]}.new(value))
|
52
|
-
end
|
53
|
-
|
54
|
-
ACCESSORS
|
55
|
-
|
56
|
-
|
57
91
|
elsif
|
58
92
|
class_properties[property_name] = nil
|
59
93
|
end
|
@@ -97,11 +131,11 @@ module Hashie
|
|
97
131
|
# You may initialize a Dash with an attributes hash
|
98
132
|
# just like you would many other kinds of data objects.
|
99
133
|
def initialize(attributes = {}, &block)
|
100
|
-
super(attributes, &block)
|
101
|
-
|
134
|
+
super(attributes, &block)
|
135
|
+
|
102
136
|
# override whatever Dash has set
|
103
137
|
attributes.each_pair do |att, value|
|
104
|
-
self.send((att.to_s + '=').to_sym,value)
|
138
|
+
self.send((att.to_s + '=').to_sym,value)
|
105
139
|
end if attributes
|
106
140
|
assert_required_properties_set!
|
107
141
|
end
|
data/nashie.gemspec
CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../lib/nash/version', __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["noverloop"]
|
6
|
-
gem.email = ["nicolas@
|
6
|
+
gem.email = ["nicolas@noverloop.be"]
|
7
7
|
gem.description = %q{Nashie is an extension of Hashie and stands for Nested Hashie. Nashie allows you to create hashes that include other objects}
|
8
8
|
gem.summary = %q{Nashie allows you to create nested Hashie structures}
|
9
9
|
gem.homepage = ""
|
data/spec/nashie_spec.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hashie::Nash do
|
4
|
+
|
5
|
+
class Test1 < Hashie::Nash
|
6
|
+
property :meh,:required => true
|
7
|
+
end
|
8
|
+
|
9
|
+
class NestedTest < Hashie::Nash
|
10
|
+
property :nest, :class => Test1
|
11
|
+
end
|
12
|
+
|
13
|
+
class NestedWithStringTest < Hashie::Nash
|
14
|
+
property :nest, :class => "Test1"
|
15
|
+
end
|
16
|
+
|
17
|
+
class Phrase < Hashie::Nash
|
18
|
+
property :phrase, :required => true
|
19
|
+
end
|
20
|
+
|
21
|
+
class NestedList < Hashie::Nash
|
22
|
+
property :nests, :class => "Phrase", :collection => true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should create a new Test1" do
|
26
|
+
t = Test1.new "meh"=> 5
|
27
|
+
t.nil?.should == false
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should create a new NestedTest" do
|
31
|
+
t = NestedTest.new "nest" => {"meh"=> 5}
|
32
|
+
t.nil?.should == false
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should make nested hashes accessible" do
|
36
|
+
t = NestedTest.new "nest" => {"meh"=> 5}
|
37
|
+
t.nest.meh.should == 5
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should make nested hashes with strings accessible" do
|
41
|
+
t = NestedWithStringTest.new "nest" => {"meh"=> 5}
|
42
|
+
t.nest.meh.should == 5
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should deal with collections of items properly" do
|
46
|
+
t = NestedList.new "nests" => [{"phrase" => "phrase 1"}, {"phrase" => "phrase 2"}]
|
47
|
+
t.nests.count.should == 2
|
48
|
+
t.nests.first.phrase.should == "phrase 1"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should make validate required properties in nested dash" do
|
52
|
+
lambda do
|
53
|
+
t = NestedTest.new "nest" => {"non_existent"=> 5}
|
54
|
+
t.nest.meh.should == 5
|
55
|
+
end.should raise_error NoMethodError
|
56
|
+
end
|
57
|
+
|
58
|
+
class Part < Hashie::Nash
|
59
|
+
property :name, :required => true
|
60
|
+
end
|
61
|
+
|
62
|
+
class Engine < Hashie::Nash
|
63
|
+
property :build_year, :required => true
|
64
|
+
property :nitro, :default => false
|
65
|
+
property :parts, :collection => true, :class => "Part"
|
66
|
+
end
|
67
|
+
|
68
|
+
class Car < Hashie::Nash
|
69
|
+
property :engine, :required => true, :class => Engine
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
it "should make validate required properties in nested dash" do
|
74
|
+
car = Car.new "engine" => {"build_year" => 2010, "nitro" => false, :parts => [{"name" => "crankshaft"}, {"name" => "flywheel"}]}
|
75
|
+
car.engine.build_year.should == 2010
|
76
|
+
car.engine.nitro.should be_false
|
77
|
+
car.engine.parts.count.should == 2
|
78
|
+
car.engine.parts.first.name.should == "crankshaft"
|
79
|
+
end
|
80
|
+
|
81
|
+
class Presentation < Hashie::Nash
|
82
|
+
property :users, :collection => true, :required => true do
|
83
|
+
property :name
|
84
|
+
end
|
85
|
+
end
|
86
|
+
require "pry"
|
87
|
+
it "should accept blocks" do
|
88
|
+
p = Presentation.new :users => [{"name"=> "Bob"}, {"name"=>"Eve"}]
|
89
|
+
p.users.count.should == 2
|
90
|
+
p.users.first.name.should == "Bob"
|
91
|
+
end
|
92
|
+
end
|
metadata
CHANGED
@@ -1,87 +1,83 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: nashie
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
4
5
|
prerelease:
|
5
|
-
version: 0.0.3
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
|
7
|
+
authors:
|
8
|
+
- noverloop
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
description: Nashie is an extension of Hashie and stands for Nested Hashie. Nashie
|
38
|
-
|
39
|
-
|
12
|
+
date: 2013-04-12 00:00:00.000000000 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hashie
|
17
|
+
requirement: &2164468960 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2164468960
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rake
|
28
|
+
requirement: &2164468400 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2164468400
|
37
|
+
description: Nashie is an extension of Hashie and stands for Nested Hashie. Nashie
|
38
|
+
allows you to create hashes that include other objects
|
39
|
+
email:
|
40
|
+
- nicolas@noverloop.be
|
40
41
|
executables: []
|
41
|
-
|
42
42
|
extensions: []
|
43
|
-
|
44
43
|
extra_rdoc_files: []
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
homepage:
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- .rspec
|
47
|
+
- Gemfile
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- lib/nash/version.rb
|
52
|
+
- lib/nashie.rb
|
53
|
+
- nashie.gemspec
|
54
|
+
- spec/nashie_spec.rb
|
55
|
+
- spec/spec_helper.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: ''
|
59
58
|
licenses: []
|
60
|
-
|
61
59
|
post_install_message:
|
62
60
|
rdoc_options: []
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
64
|
none: false
|
68
|
-
requirements:
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
70
|
none: false
|
74
|
-
requirements:
|
75
|
-
|
76
|
-
|
77
|
-
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
78
75
|
requirements: []
|
79
|
-
|
80
76
|
rubyforge_project:
|
81
|
-
rubygems_version: 1.
|
77
|
+
rubygems_version: 1.5.2
|
82
78
|
signing_key:
|
83
79
|
specification_version: 3
|
84
80
|
summary: Nashie allows you to create nested Hashie structures
|
85
|
-
test_files:
|
86
|
-
|
87
|
-
|
81
|
+
test_files:
|
82
|
+
- spec/nashie_spec.rb
|
83
|
+
- spec/spec_helper.rb
|
data/spec/nash_spec.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Nash do
|
4
|
-
|
5
|
-
class Test1 < Hashie::Nash
|
6
|
-
property :meh,:required => true
|
7
|
-
end
|
8
|
-
|
9
|
-
class NestedTest < Hashie::Nash
|
10
|
-
property :nest, :class => Test1
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should create a new Test1" do
|
14
|
-
t = Test1.new "meh"=> 5
|
15
|
-
t.nil?.should == false
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should create a new NestedTest" do
|
19
|
-
t = NestedTest.new "nest" => {"meh"=> 5}
|
20
|
-
t.nil?.should == false
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should make nested hashes accessible" do
|
24
|
-
t = NestedTest.new "nest" => {"meh"=> 5}
|
25
|
-
t.nest.meh.should == 5
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should make validate required properties in nested dash" do
|
29
|
-
lambda do
|
30
|
-
t = NestedTest.new "nest" => {"non_existent"=> 5}
|
31
|
-
t.nest.meh.should == 5
|
32
|
-
end.should raise_error NoMethodError
|
33
|
-
end
|
34
|
-
|
35
|
-
class Car < Hashie::Nash
|
36
|
-
class Engine < Hashie::Nash
|
37
|
-
property :crankshaft, :required => true
|
38
|
-
property :nitro, :default => false
|
39
|
-
end
|
40
|
-
property :engine, :required => true, :class => Engine
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
it "should make validate required properties in nested dash" do
|
45
|
-
c = Car.new "engine" => {"crankshaft" => true, "nitro" => false}
|
46
|
-
c.engine.crankshaft.should == true
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|