cistern 0.0.3 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .rspec
data/Gemfile CHANGED
@@ -2,3 +2,16 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in cistern.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem "rspec", "~> 2.0"
8
+ gem "guard-rspec"
9
+ gem "rake"
10
+ gem 'rb-fsevent', '~> 0.9.1'
11
+ end
12
+
13
+ group :formatters do
14
+ gem 'formatador'
15
+ gem 'awesome_print'
16
+ end
17
+
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Cistern
2
2
 
3
+ [![Build Status](https://secure.travis-ci.org/lanej/cistern.png)](http://travis-ci.org/lanej/cistern)
4
+
3
5
  TODO: Write a gem description
4
6
 
5
7
  ## Installation
@@ -20,10 +22,14 @@ Or install it yourself as:
20
22
 
21
23
  TODO: Write usage instructions here
22
24
 
25
+ ## Releasing
26
+
27
+ $ gem bump -trv (major|minor|patch)
28
+
23
29
  ## Contributing
24
30
 
25
31
  1. Fork it
26
32
  2. Create your feature branch (`git checkout -b my-new-feature`)
27
33
  3. Commit your changes (`git commit -am 'Added some feature'`)
28
34
  4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
35
+ . Create new Pull Request
data/Rakefile CHANGED
@@ -1,2 +1,5 @@
1
1
  #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:default)
data/cistern.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
6
6
  gem.email = ["me@joshualane.com"]
7
7
  gem.description = %q{API client framework extracted from Fog}
8
8
  gem.summary = %q{API client framework}
9
- gem.homepage = ""
9
+ gem.homepage = "http://joshualane.com/cistern"
10
10
 
11
11
  gem.files = `git ls-files`.split($\)
12
12
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -14,6 +14,4 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "cistern"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Cistern::VERSION
17
-
18
- gem.add_dependency "formatador"
19
17
  end
@@ -1,203 +1,173 @@
1
- module Cistern
2
- module Attributes
3
- module ClassMethods
4
-
5
- def _load(marshalled)
6
- new(Marshal.load(marshalled))
7
- end
8
-
9
- def aliases
10
- @aliases ||= {}
11
- end
12
-
13
- def attributes
14
- @attributes ||= []
15
- end
1
+ module Cistern::Attributes
2
+ def self.parsers
3
+ @parsers ||= {
4
+ :string => lambda{|v,opts| v.to_s},
5
+ :time => lambda{|v,opts| v.is_a?(Time) ? v : v && Time.parse(v.to_s)},
6
+ :integer => lambda{|v,opts| v && v.to_i},
7
+ :float => lambda{|v,opts| v && v.to_f},
8
+ :array => lambda{|v,opts| [*v]},
9
+ :boolean => Proc.new do |v, opts|
10
+ {
11
+ true => true,
12
+ "true" => true,
13
+ "1" => true,
14
+ 1 => true,
15
+ false => false,
16
+ "false" => false,
17
+ "0" => false,
18
+ 0 => false,
19
+ }[v]
20
+ end,
21
+ }
22
+ end
16
23
 
17
- def attribute(name, options = {})
18
- class_eval <<-EOS, __FILE__, __LINE__
19
- def #{name}
20
- attributes[:#{name}]
21
- end
22
- EOS
23
- case options[:type]
24
- when :boolean
25
- class_eval <<-EOS, __FILE__, __LINE__
26
- def #{name}=(new_#{name})
27
- attributes[:#{name}] = case new_#{name}
28
- when true,'true'
29
- true
30
- when false,'false'
31
- false
32
- end
33
- end
34
- EOS
35
- when :float
36
- class_eval <<-EOS, __FILE__, __LINE__
37
- def #{name}=(new_#{name})
38
- attributes[:#{name}] = new_#{name} && new_#{name}.to_f
39
- end
40
- EOS
41
- when :integer
42
- class_eval <<-EOS, __FILE__, __LINE__
43
- def #{name}=(new_#{name})
44
- attributes[:#{name}] = new_#{name} && new_#{name}.to_i
45
- end
46
- EOS
47
- when :string
48
- class_eval <<-EOS, __FILE__, __LINE__
49
- def #{name}=(new_#{name})
50
- attributes[:#{name}] = new_#{name} && new_#{name}.to_s
51
- end
52
- EOS
53
- when :time
54
- class_eval <<-EOS, __FILE__, __LINE__
55
- def #{name}=(new_#{name})
56
- attributes[:#{name}] = if new_#{name}.nil? || new_#{name} == "" || new_#{name}.is_a?(Time)
57
- new_#{name}
58
- else
59
- Time.parse(new_#{name})
60
- end
61
- end
62
- EOS
63
- when :array
64
- class_eval <<-EOS, __FILE__, __LINE__
65
- def #{name}=(new_#{name})
66
- attributes[:#{name}] = [*new_#{name}]
67
- end
68
- EOS
69
- else
70
- if squash = options[:squash]
71
- class_eval <<-EOS, __FILE__, __LINE__
72
- def #{name}=(new_data)
73
- if new_data.is_a?(::Hash)
74
- if new_data.has_key?(:'#{squash}')
75
- attributes[:#{name}] = new_data[:'#{squash}']
76
- elsif new_data.has_key?("#{squash}")
77
- attributes[:#{name}] = new_data["#{squash}"]
78
- else
79
- attributes[:#{name}] = [ new_data ]
80
- end
81
- else
82
- attributes[:#{name}] = new_data
83
- end
84
- end
85
- EOS
24
+ def self.transforms
25
+ @transforms ||= {
26
+ :squash => Proc.new do |k, v, options|
27
+ squash = options[:squash]
28
+ if v.is_a?(::Hash)
29
+ if v.key?(squash.to_s.to_sym)
30
+ v[squash.to_s.to_sym]
31
+ elsif v.has_key?(squash.to_s)
32
+ v[squash.to_s]
86
33
  else
87
- class_eval <<-EOS, __FILE__, __LINE__
88
- def #{name}=(new_#{name})
89
- attributes[:#{name}] = new_#{name}
90
- end
91
- EOS
34
+ v
92
35
  end
36
+ else v
93
37
  end
94
- @attributes ||= []
95
- @attributes |= [name]
96
- for new_alias in [*options[:aliases]]
97
- aliases[new_alias] = name
98
- end
99
- end
38
+ end,
39
+ :none => lambda{|k, v, opts| v},
40
+ }
41
+ end
100
42
 
101
- def identity(name, options = {})
102
- @identity = name
103
- self.attribute(name, options)
104
- end
43
+ def self.default_parser
44
+ @default_parser ||= lambda{|v, opts| v}
45
+ end
105
46
 
106
- def ignore_attributes(*args)
107
- @ignored_attributes = args
108
- end
47
+ module ClassMethods
48
+ def _load(marshalled)
49
+ new(Marshal.load(marshalled))
50
+ end
109
51
 
110
- def ignored_attributes
111
- @ignored_attributes ||= []
112
- end
52
+ def aliases
53
+ @aliases ||= {}
54
+ end
113
55
 
56
+ def attributes
57
+ @attributes ||= []
114
58
  end
115
59
 
116
- module InstanceMethods
60
+ def attribute(name, options = {})
61
+ parser = Cistern::Attributes.parsers[options[:type]] ||
62
+ options[:parser] ||
63
+ Cistern::Attributes.default_parser
64
+ transform = Cistern::Attributes.transforms[options[:squash] ? :squash : :none] ||
65
+ Cistern::Attributes.default_transform
117
66
 
118
- def _dump(level)
119
- Marshal.dump(attributes)
67
+ self.send(:define_method, name) do
68
+ attributes[name.to_s.to_sym]
120
69
  end
121
70
 
122
- def attributes
123
- @attributes ||= {}
71
+ self.send(:define_method, "#{name}=") do |value|
72
+ transformed = transform.call(name, value, options)
73
+ attributes[name.to_s.to_sym]= parser.call(transformed, options)
124
74
  end
125
75
 
126
- def dup
127
- copy = super
128
- copy.dup_attributes!
129
- copy
130
- end
76
+ @attributes ||= []
77
+ @attributes |= [name]
131
78
 
132
- def identity
133
- send(self.class.instance_variable_get('@identity'))
79
+ for new_alias in [*options[:aliases]]
80
+ aliases[new_alias] = name
134
81
  end
82
+ end
135
83
 
136
- def identity=(new_identity)
137
- send("#{self.class.instance_variable_get('@identity')}=", new_identity)
138
- end
84
+ def identity(name, options = {})
85
+ @identity = name
86
+ self.attribute(name, options)
87
+ end
139
88
 
140
- def merge_attributes(new_attributes = {})
141
- for key, value in new_attributes
142
- unless self.class.ignored_attributes.include?(key)
143
- if aliased_key = self.class.aliases[key]
144
- send("#{aliased_key}=", value)
145
- elsif self.respond_to?("#{key}=",true)
146
- send("#{key}=", value)
147
- else
148
- attributes[key] = value
149
- end
150
- end
151
- end
152
- self
153
- end
89
+ def ignore_attributes(*args)
90
+ @ignored_attributes = args
91
+ end
154
92
 
155
- def new_record?
156
- !identity
157
- end
93
+ def ignored_attributes
94
+ @ignored_attributes ||= []
95
+ end
96
+ end
158
97
 
159
- # check that the attributes specified in args exist and is not nil
160
- def requires(*args)
161
- missing = missing_attributes(args)
162
- if missing.length == 1
163
- raise(ArgumentError, "#{missing.first} is required for this operation")
164
- elsif missing.any?
165
- raise(ArgumentError, "#{missing[0...-1].join(", ")} and #{missing[-1]} are required for this operation")
166
- end
167
- end
98
+ module InstanceMethods
99
+ def _dump(level)
100
+ Marshal.dump(attributes)
101
+ end
168
102
 
169
- def requires_one(*args)
170
- missing = missing_attributes(args)
171
- if missing.length == args.length
172
- raise(ArgumentError, "#{missing[0...-1].join(", ")} or #{missing[-1]} are required for this operation")
173
- end
174
- end
103
+ def attributes
104
+ @attributes ||= {}
105
+ end
175
106
 
176
- protected
107
+ def attributes=(attributes)
108
+ @attributes = attributes
109
+ end
110
+
111
+ def dup
112
+ copy = super
113
+ copy.attributes= copy.attributes.dup
114
+ copy
115
+ end
177
116
 
178
- def missing_attributes(args)
179
- missing = []
180
- for arg in [:connection] | args
181
- unless send("#{arg}") || attributes.has_key?(arg)
182
- missing << arg
117
+ def identity
118
+ send(self.class.instance_variable_get('@identity'))
119
+ end
120
+
121
+ def identity=(new_identity)
122
+ send("#{self.class.instance_variable_get('@identity')}=", new_identity)
123
+ end
124
+
125
+ def merge_attributes(new_attributes = {})
126
+ for key, value in new_attributes
127
+ unless self.class.ignored_attributes.include?(key)
128
+ if aliased_key = self.class.aliases[key]
129
+ send("#{aliased_key}=", value)
130
+ elsif self.respond_to?("#{key}=", true)
131
+ send("#{key}=", value)
132
+ else
133
+ attributes[key] = value
183
134
  end
184
135
  end
185
- missing
186
136
  end
137
+ self
138
+ end
187
139
 
188
- def dup_attributes!
189
- @attributes = @attributes.dup
140
+ def new_record?
141
+ !identity
142
+ end
143
+
144
+ # check that the attributes specified in args exist and is not nil
145
+ def requires(*args)
146
+ missing = missing_attributes(args)
147
+ if missing.length == 1
148
+ raise(ArgumentError, "#{missing.first} is required for this operation")
149
+ elsif missing.any?
150
+ raise(ArgumentError, "#{missing[0...-1].join(", ")} and #{missing[-1]} are required for this operation")
151
+ end
152
+ end
153
+
154
+ def requires_one(*args)
155
+ missing = missing_attributes(args)
156
+ if missing.length == args.length
157
+ raise(ArgumentError, "#{missing[0...-1].join(", ")} or #{missing[-1]} are required for this operation")
190
158
  end
159
+ end
191
160
 
192
- private
161
+ protected
193
162
 
194
- def remap_attributes(attributes, mapping)
195
- for key, value in mapping
196
- if attributes.key?(key)
197
- attributes[value] = attributes.delete(key)
198
- end
163
+ def missing_attributes(args)
164
+ missing = []
165
+ for arg in [:connection] | args
166
+ unless send("#{arg}") || attributes.has_key?(arg)
167
+ missing << arg
199
168
  end
200
169
  end
170
+ missing
201
171
  end
202
172
  end
203
173
  end
@@ -2,29 +2,23 @@ class Cistern::Collection < Array
2
2
  extend Cistern::Attributes::ClassMethods
3
3
  include Cistern::Attributes::InstanceMethods
4
4
 
5
- Array.public_instance_methods(false).each do |method|
6
- unless [:reject, :select, :slice].include?(method.to_sym)
7
- class_eval <<-EOS, __FILE__, __LINE__
8
- def #{method}(*args)
9
- unless @loaded
10
- lazy_load
11
- end
12
- super
13
- end
14
- EOS
5
+ %w[reject select slice].each do |method|
6
+ define_method(method) do |*args, &block|
7
+ unless @loaded
8
+ lazy_load
9
+ end
10
+ data = super(*args, &block)
11
+ self.clone.clear.concat(data)
15
12
  end
16
13
  end
17
14
 
18
- %w[reject select slice].each do |method|
19
- class_eval <<-EOS, __FILE__, __LINE__
20
- def #{method}(*args)
21
- unless @loaded
22
- lazy_load
23
- end
24
- data = super
25
- self.clone.clear.concat(data)
15
+ %w[first last].each do |method|
16
+ define_method(method) do
17
+ unless @loaded
18
+ lazy_load
26
19
  end
27
- EOS
20
+ super()
21
+ end
28
22
  end
29
23
 
30
24
  def self.model(new_model=nil)
@@ -80,40 +74,12 @@ class Cistern::Collection < Array
80
74
  self
81
75
  end
82
76
 
83
- def inspect
84
- Thread.current[:formatador] ||= Formatador.new
85
- data = "#{Thread.current[:formatador].indentation}<#{self.class.name}\n"
86
- Thread.current[:formatador].indent do
87
- unless self.class.attributes.empty?
88
- data << "#{Thread.current[:formatador].indentation}"
89
- data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
90
- data << "\n"
91
- end
92
- data << "#{Thread.current[:formatador].indentation}["
93
- unless self.empty?
94
- data << "\n"
95
- Thread.current[:formatador].indent do
96
- data << self.map {|member| member.inspect}.join(",\n")
97
- data << "\n"
98
- end
99
- data << Thread.current[:formatador].indentation
100
- end
101
- data << "]\n"
102
- end
103
- data << "#{Thread.current[:formatador].indentation}>"
104
- data
105
- end
106
-
107
77
  def reload
108
78
  clear
109
79
  lazy_load
110
80
  self
111
81
  end
112
82
 
113
- def table(attributes = nil)
114
- Formatador.display_table(self.map {|instance| instance.attributes}, attributes)
115
- end
116
-
117
83
  private
118
84
 
119
85
  def lazy_load
@@ -0,0 +1,5 @@
1
+ module Cistern::Formatter
2
+ autoload :AwesomePrint, 'cistern/formatters/awesome_print'
3
+ autoload :Default, 'cistern/formatters/default'
4
+ autoload :Formatador, 'cistern/formatters/formatador'
5
+ end
@@ -0,0 +1,31 @@
1
+ require 'awesome_print'
2
+
3
+ module Cistern::Formatter::AwesomePrint
4
+ def self.call(model)
5
+ model.ai
6
+ end
7
+ end
8
+
9
+ module AwesomePrint::Cistern
10
+ def self.included(base)
11
+ base.send :alias_method, :cast_without_cistern, :cast
12
+ base.send :alias_method, :cast, :cast_with_cistern
13
+ end
14
+
15
+ def cast_with_cistern(object, type)
16
+ cast = cast_without_cistern(object, type)
17
+ if object.is_a?(Cistern::Model)
18
+ cast = :cistern_model
19
+ end
20
+ cast
21
+ end
22
+
23
+ # Format Cistern::Model
24
+ #------------------------------------------------------------------------------
25
+ def awesome_cistern_model(object)
26
+ data = object.attributes.keys.inject({}){|r,k| r.merge(k => object.send(k))}
27
+ "#{object} " << awesome_hash(data)
28
+ end
29
+ end
30
+
31
+ AwesomePrint::Formatter.send(:include, AwesomePrint::Cistern)
@@ -0,0 +1,5 @@
1
+ module Cistern::Formatter::Default
2
+ def self.call(obj)
3
+ "#<%s:0x%x attributes={%s}>" % [obj.class, obj.object_id.abs*2, obj.attributes.map{|k,v| "#{k}:#{v.inspect}"}.join(",")]
4
+ end
5
+ end
@@ -0,0 +1,44 @@
1
+ require 'formatador'
2
+
3
+ module Cistern::Formatter::Formatador
4
+ def self.call(model)
5
+ Thread.current[:formatador] ||= Formatador.new
6
+ data = "#{Thread.current[:formatador].indentation}<#{model.class.name}"
7
+ Thread.current[:formatador].indent do
8
+ unless model.class.attributes.empty?
9
+ data << "\n#{Thread.current[:formatador].indentation}"
10
+ data << model.class.attributes.map {|attribute| "#{attribute}=#{model.send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
11
+ end
12
+ end
13
+ data << "\n#{Thread.current[:formatador].indentation}>"
14
+ data
15
+ end
16
+
17
+ def inspect
18
+ Thread.current[:formatador] ||= Formatador.new
19
+ data = "#{Thread.current[:formatador].indentation}<#{self.class.name}\n"
20
+ Thread.current[:formatador].indent do
21
+ unless self.class.attributes.empty?
22
+ data << "#{Thread.current[:formatador].indentation}"
23
+ data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
24
+ data << "\n"
25
+ end
26
+ data << "#{Thread.current[:formatador].indentation}["
27
+ unless self.empty?
28
+ data << "\n"
29
+ Thread.current[:formatador].indent do
30
+ data << self.map {|member| member.inspect}.join(",\n")
31
+ data << "\n"
32
+ end
33
+ data << Thread.current[:formatador].indentation
34
+ end
35
+ data << "]\n"
36
+ end
37
+ data << "#{Thread.current[:formatador].indentation}>"
38
+ data
39
+ end
40
+
41
+ def table(attributes = nil)
42
+ Formatador.display_table(self.map {|instance| instance.attributes}, attributes)
43
+ end
44
+ end
data/lib/cistern/model.rb CHANGED
@@ -4,23 +4,21 @@ class Cistern::Model
4
4
 
5
5
  attr_accessor :collection, :connection
6
6
 
7
- def initialize(attributes={})
8
- merge_attributes(attributes)
7
+ def self.formatter
8
+ @formatter ||= Cistern::Formatter::Default
9
+ end
10
+
11
+ def self.formatter=(formatter)
12
+ @formatter = formatter
9
13
  end
10
14
 
11
15
  def inspect
12
- Thread.current[:formatador] ||= Formatador.new
13
- data = "#{Thread.current[:formatador].indentation}<#{self.class.name}"
14
- Thread.current[:formatador].indent do
15
- unless self.class.attributes.empty?
16
- data << "\n#{Thread.current[:formatador].indentation}"
17
- data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
18
- end
19
- end
20
- data << "\n#{Thread.current[:formatador].indentation}>"
21
- data
16
+ self.class.formatter.call(self)
22
17
  end
23
18
 
19
+ def initialize(attributes={})
20
+ merge_attributes(attributes)
21
+ end
24
22
 
25
23
  def save
26
24
  raise NotImplementedError
@@ -1,3 +1,3 @@
1
1
  module Cistern
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.2"
3
3
  end
data/lib/cistern.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'cistern/version'
2
- require 'formatador'
2
+ require 'time'
3
3
 
4
4
  module Cistern
5
5
  Error = Class.new(StandardError)
@@ -12,6 +12,9 @@ module Cistern
12
12
  require 'cistern/model'
13
13
  require 'cistern/service'
14
14
 
15
+ autoload :Formatter, 'cistern/formatter'
16
+
17
+
15
18
  def self.timeout=(timeout)
16
19
  @timeout= timeout
17
20
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Cistern::Collection" do
4
+ class SampleCollectionModel < Cistern::Model
5
+ identity :id
6
+ attribute :name
7
+ end
8
+ class SampleCollection < Cistern::Collection
9
+ model SampleCollectionModel
10
+
11
+ def all
12
+ self.load([{id: 1}, {id: 3, name: "tom"}, {id: 2}])
13
+ end
14
+ end
15
+
16
+ it "should give first" do
17
+ SampleCollection.new.first.should == SampleCollectionModel.new(id: 1)
18
+ end
19
+
20
+ it "should give last" do
21
+ SampleCollection.new.last.should == SampleCollectionModel.new(id: 2)
22
+ end
23
+
24
+ it "should reject" do
25
+ SampleCollection.new.reject{|m| m.id == 2}.should == [SampleCollectionModel.new(id: 1), SampleCollectionModel.new(id: 3)]
26
+ end
27
+
28
+ it "should select" do
29
+ SampleCollection.new.select{|m| m.id == 2}.should == [SampleCollectionModel.new(id: 2)]
30
+ end
31
+
32
+ it "should slice" do
33
+ SampleCollection.new.slice(0,2).should == [SampleCollectionModel.new(id: 1), SampleCollectionModel.new(id: 3, name: "tom")]
34
+ end
35
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Cistern::Model" do
4
+
5
+ it "should duplicate a model" do
6
+ class DupSpec < Cistern::Model
7
+ identity :id
8
+ attribute :name
9
+ attribute :properties
10
+ end
11
+
12
+ model = DupSpec.new(id: 1, name: "string", properties: {value: "something", else: "what"})
13
+ duplicate = model.dup
14
+
15
+ duplicate.should == model
16
+ duplicate.should_not eql model
17
+
18
+ model.name= "anotherstring"
19
+ duplicate.name.should == "string"
20
+ end
21
+
22
+ context "attribute parsing" do
23
+ class TypeSpec < Cistern::Model
24
+ identity :id
25
+ attribute :name, type: :string
26
+ attribute :created_at, type: :time
27
+ attribute :flag, type: :boolean
28
+ attribute :list, type: :array
29
+ attribute :number, type: :integer
30
+ attribute :floater, type: :float
31
+ attribute :butternut, type: :integer, aliases: "squash", squash: "id"
32
+ attribute :custom, parser: lambda{|v, opts| "X!#{v}"}
33
+ end
34
+
35
+ it "should parse string" do
36
+ TypeSpec.new(name: 1).name.should == "1"
37
+ end
38
+
39
+ it "should parse time" do
40
+ time = Time.now
41
+ created_at = TypeSpec.new(created_at: time.to_s).created_at
42
+ created_at.should be_a(Time)
43
+ created_at.to_i.should == time.to_i
44
+ end
45
+
46
+ it "should parse boolean" do
47
+ TypeSpec.new(flag: "false").flag.should be_false
48
+ TypeSpec.new(flag: "true").flag.should be_true
49
+ TypeSpec.new(flag: false).flag.should be_false
50
+ TypeSpec.new(flag: true).flag.should be_true
51
+ TypeSpec.new(flag: "0").flag.should be_false
52
+ TypeSpec.new(flag: "1").flag.should be_true
53
+ TypeSpec.new(flag: 0).flag.should be_false
54
+ TypeSpec.new(flag: 1).flag.should be_true
55
+ end
56
+
57
+ it "should parse an array" do
58
+ TypeSpec.new(list: []).list.should == []
59
+ TypeSpec.new(list: "item").list.should == ["item"]
60
+ end
61
+
62
+ it "should parse a float" do
63
+ TypeSpec.new(floater: "0.01").floater.should == 0.01
64
+ TypeSpec.new(floater: 0.01).floater.should == 0.01
65
+ end
66
+
67
+ it "should use custom parser" do
68
+ TypeSpec.new(custom: "15").custom.should == "X!15"
69
+ end
70
+
71
+ it "should squash and cast" do
72
+ TypeSpec.new({"squash" => {"id" => "12"}}).butternut.should == 12
73
+ end
74
+ end
75
+
76
+ context "inspection engine" do
77
+ class InspectorSpec < Cistern::Model
78
+ identity :id
79
+ attribute :name
80
+ end
81
+
82
+ after(:all) do
83
+ InspectorSpec.formatter= Cistern::Formatter::Default
84
+ end
85
+
86
+ it "should default to default formatter" do
87
+ InspectorSpec.formatter.should == Cistern::Formatter::Default
88
+ end
89
+
90
+ it "should use default" do
91
+ InspectorSpec.new(id: 1, name: "name").inspect.should match /#<InspectorSpec:0x[0-9a-f]+ attributes={id:1,name:\"name\"}/
92
+ end
93
+
94
+ it "should use awesome_print" do
95
+ defined?(AwesomePrint).should be_false # don't require if not used
96
+ InspectorSpec.formatter= Cistern::Formatter::AwesomePrint
97
+
98
+ InspectorSpec.new(id: 1, name: "name").inspect.match /(?x-mi:\#<InspectorSpec:0x[0-9a-f]+>\ {\n\ \ \ \ \ \ :id\x1B\[0;37m\ =>\ \x1B\[0m\x1B\[1;34m1\x1B\[0m,\n\ \ \ \ :name\x1B\[0;37m\ =>\ \x1B\[0m\x1B\[0;33m"name"\x1B\[0m\n})/
99
+ end
100
+
101
+ it "should use formatador" do
102
+ defined?(Formatador).should be_false # don't require if not used
103
+ InspectorSpec.formatter= Cistern::Formatter::Formatador
104
+
105
+ InspectorSpec.new(id: 1, name: "name").inspect.should == " <InspectorSpec\n id=1,\n name=\"name\"\n >"
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path('../../lib/cistern', __FILE__)
2
+
3
+ Bundler.require(:test)
4
+
5
+ RSpec.configure do
6
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cistern
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,24 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-21 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: formatador
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
12
+ date: 2012-11-30 00:00:00.000000000 Z
13
+ dependencies: []
30
14
  description: API client framework extracted from Fog
31
15
  email:
32
16
  - me@joshualane.com
@@ -36,6 +20,7 @@ extra_rdoc_files: []
36
20
  files:
37
21
  - .gitignore
38
22
  - Gemfile
23
+ - Guardfile
39
24
  - LICENSE
40
25
  - README.md
41
26
  - Rakefile
@@ -43,13 +28,20 @@ files:
43
28
  - lib/cistern.rb
44
29
  - lib/cistern/attributes.rb
45
30
  - lib/cistern/collection.rb
31
+ - lib/cistern/formatter.rb
32
+ - lib/cistern/formatters/awesome_print.rb
33
+ - lib/cistern/formatters/default.rb
34
+ - lib/cistern/formatters/formatador.rb
46
35
  - lib/cistern/hash.rb
47
36
  - lib/cistern/mock.rb
48
37
  - lib/cistern/model.rb
49
38
  - lib/cistern/service.rb
50
39
  - lib/cistern/version.rb
51
40
  - lib/cistern/wait_for.rb
52
- homepage: ''
41
+ - spec/collection_spec.rb
42
+ - spec/model_spec.rb
43
+ - spec/spec_helper.rb
44
+ homepage: http://joshualane.com/cistern
53
45
  licenses: []
54
46
  post_install_message:
55
47
  rdoc_options: []
@@ -73,4 +65,7 @@ rubygems_version: 1.8.24
73
65
  signing_key:
74
66
  specification_version: 3
75
67
  summary: API client framework
76
- test_files: []
68
+ test_files:
69
+ - spec/collection_spec.rb
70
+ - spec/model_spec.rb
71
+ - spec/spec_helper.rb