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 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