nashie 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -4,5 +4,6 @@ source 'https://rubygems.org'
4
4
 
5
5
  group :test do
6
6
  gem "rspec"
7
+ gem "pry"
7
8
  end
8
9
  gemspec
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Nashie
2
- Nashie provides a Hashie that can nest other Hashies.
3
- This allows you to rapidly create complex nested hashes.
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 < Hashie::Nash
23
- property :crankshaft, :required => true
24
- property :nitro, :default => false
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
- Car.new "engine" => {"crankshaft" => true, "nitro" => false}
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
@@ -1,3 +1,3 @@
1
1
  module Nash
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.5"
3
3
  end
data/lib/nashie.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  require "nash/version"
2
- require 'hashie/dash'
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
- # Nashes are useful when you need to create a lightweigth nested
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::Dash
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
- class_eval <<-ACCESSORS
46
- def #{property_name}(&block)
47
- self.[](#{property_name.to_s.inspect}, &block)
48
- end
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@geckoboard.com"]
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 = ""
@@ -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
- - noverloop
7
+ authors:
8
+ - noverloop
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2012-06-09 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: hashie
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
24
- type: :runtime
25
- version_requirements: *id001
26
- - !ruby/object:Gem::Dependency
27
- name: rake
28
- prerelease: false
29
- requirement: &id002 !ruby/object:Gem::Requirement
30
- none: false
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: "0"
35
- type: :development
36
- version_requirements: *id002
37
- description: Nashie is an extension of Hashie and stands for Nested Hashie. Nashie allows you to create hashes that include other objects
38
- email:
39
- - nicolas@geckoboard.com
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
- files:
47
- - .gitignore
48
- - .rspec
49
- - Gemfile
50
- - LICENSE
51
- - README.md
52
- - Rakefile
53
- - lib/nash/version.rb
54
- - lib/nashie.rb
55
- - nashie.gemspec
56
- - spec/nash_spec.rb
57
- - spec/spec_helper.rb
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
- require_paths:
65
- - lib
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
- - !ruby/object:Gem::Version
71
- version: "0"
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
- - !ruby/object:Gem::Version
77
- version: "0"
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
78
75
  requirements: []
79
-
80
76
  rubyforge_project:
81
- rubygems_version: 1.8.9
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
- - spec/nash_spec.rb
87
- - spec/spec_helper.rb
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