yaks 0.7.6 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -0
  3. data/Rakefile +58 -38
  4. data/lib/yaks.rb +3 -4
  5. data/lib/yaks/attributes.rb +23 -10
  6. data/lib/yaks/config.rb +4 -0
  7. data/lib/yaks/configurable.rb +16 -21
  8. data/lib/yaks/format.rb +1 -1
  9. data/lib/yaks/format/collection_json.rb +9 -0
  10. data/lib/yaks/format/halo.rb +16 -13
  11. data/lib/yaks/html5_forms.rb +22 -1
  12. data/lib/yaks/mapper.rb +5 -5
  13. data/lib/yaks/mapper/attribute.rb +1 -1
  14. data/lib/yaks/mapper/class_methods.rb +3 -1
  15. data/lib/yaks/mapper/config.rb +9 -16
  16. data/lib/yaks/mapper/form.rb +41 -0
  17. data/lib/yaks/mapper/form/field.rb +62 -0
  18. data/lib/yaks/null_resource.rb +1 -1
  19. data/lib/yaks/resource.rb +7 -3
  20. data/lib/yaks/resource/form.rb +31 -0
  21. data/lib/yaks/runner.rb +11 -11
  22. data/lib/yaks/stateful_builder.rb +11 -7
  23. data/lib/yaks/util.rb +3 -2
  24. data/lib/yaks/version.rb +1 -1
  25. data/spec/acceptance/models.rb +1 -1
  26. data/spec/json/confucius.halo.json +2 -4
  27. data/spec/json/plant_collection.collection.json +4 -0
  28. data/spec/unit/yaks/attributes_spec.rb +79 -0
  29. data/spec/unit/yaks/configurable_spec.rb +32 -2
  30. data/spec/unit/yaks/format/collection_json_spec.rb +59 -27
  31. data/spec/unit/yaks/format/halo_spec.rb +3 -0
  32. data/spec/unit/yaks/mapper/{control → form}/field_spec.rb +3 -3
  33. data/spec/unit/yaks/mapper/{control_spec.rb → form_spec.rb} +12 -12
  34. data/spec/unit/yaks/mapper_spec.rb +10 -10
  35. data/spec/unit/yaks/null_resource_spec.rb +50 -7
  36. data/spec/unit/yaks/resource_spec.rb +4 -4
  37. data/spec/unit/yaks/runner_spec.rb +38 -2
  38. data/spec/unit/yaks/util_spec.rb +42 -0
  39. metadata +20 -58
  40. data/lib/yaks/mapper/control.rb +0 -82
  41. data/lib/yaks/resource/control.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3eb709b078f05c15a877f6c3008df313d09e2bbe
4
- data.tar.gz: cd8d14498bbf3c74b2362b66c30dee5ec00d3c53
3
+ metadata.gz: 207388cedc68055dcef4f732bd82ce81180871c8
4
+ data.tar.gz: 97c121f6e231e8a409d1b2bca7515d75f42d261a
5
5
  SHA512:
6
- metadata.gz: 4cc2b5d05868b2869684481a6a9a37d513b66da63dfe995307b1c2c933ab349bf0bf200f5342e60ef485f756046e2308854227f895ec1b302ed4ec0b91f1d6c8
7
- data.tar.gz: cde85afd3d63e33420ebe61e24638f1d00ceb26f93db91f48f19f42f7de531d4cd84e17dc7e74586a95afd5369d22293b4431f2208073a2ac48d84788bb67526
6
+ metadata.gz: fd61481333faaccde1120268996ab50462dcfd2c04f0b08e9340300ad6567a7bf47d59eae2b36471d9661cb9c020304566df8267c3c19f262a77346b7924504e
7
+ data.tar.gz: 3acfcdfa41752e295833ca61052fbad706e51bae6132eb7f72350bbfd5db1e0d6fa42d1338059d6fa758396d48d417f2c699a8fcfc40888074afde7189c03dfb
data/README.md CHANGED
@@ -23,6 +23,23 @@ requested. These formats are presently supported:
23
23
  * HTML
24
24
  * HALO
25
25
 
26
+ ## State of Development
27
+
28
+ This library came into existence because we at
29
+ [Ticketsolve](https://www.ticketsolve.com) wanted to build a rich
30
+ hypermedia API, and were dissatisfied with any of the existing Ruby
31
+ solutions at the time (November 2013).
32
+
33
+ We are still actively expanding our API, and with that Yaks continues
34
+ to grow and improve. The aim is to create *the reference* for
35
+ supporting hypermedia formats in Ruby.
36
+
37
+ Yaks can be used in production today, as we do, but until 1.0 is
38
+ released there will regularly be breaking changes, as we figure out
39
+ the best way to do things. These are all documented clearly in the
40
+ [changelog](CHANGLOG.md). At this point we recommend locking to an
41
+ exact version number.
42
+
26
43
  ## Concepts
27
44
 
28
45
  Yaks is a processing pipeline, you create and configure the pipeline,
data/Rakefile CHANGED
@@ -2,49 +2,69 @@ load '../rakelib/shared.rake'
2
2
 
3
3
  gem_tasks(:yaks)
4
4
 
5
-
6
5
  task :mutant_chunked do
6
+ # No subjects:
7
+ # Yaks,
8
+ # Yaks::Error,
9
+ # Yaks::IllegalStateError,
10
+ # Yaks::UnsupportedOperationError,
11
+ # Yaks::PrimitivizeError,
12
+ # Yaks::Undefined,
13
+ # Yaks::HTML5Forms,
14
+
15
+ # Hangs:
16
+ # Yaks::Changelog,
17
+
18
+ # 100% verified:
19
+ # Yaks::Util,
20
+ # Yaks::Util::Deprecated,
21
+ # Yaks::FP
22
+ # Yaks::FP::Callable,
23
+ # Yaks::DefaultPolicy,
24
+ # Yaks::Mapper::HasOne,
25
+ # Yaks::Mapper::HasMany,
26
+ # Yaks::Mapper::Attribute,
27
+ # Yaks::Mapper::Config,
28
+ # Yaks::Mapper::ClassMethods,
29
+ # Yaks::Mapper::AssociationMapper,
30
+ # Yaks::Format::CollectionJson,
31
+ # Yaks::Config,
32
+ # Yaks::Config::DSL,
33
+ # Yaks::Attributes::InstanceMethods,
34
+ # Yaks::Configurable,
35
+ # Yaks::NullResource,
36
+
7
37
  [
8
- Yaks::Attributes,
9
- Yaks::Attributes::InstanceMethods,
10
- Yaks::CollectionMapper,
11
- Yaks::CollectionResource,
12
- Yaks::Config,
13
- Yaks::Config::DSL,
14
- Yaks::Configurable,
15
- Yaks::Configurable::ClassMethods,
16
- Yaks::StatefulBuilder,
17
- Yaks::DefaultPolicy,
18
- Yaks::FP,
19
- Yaks::FP::Callable,
20
- Yaks::Format,
21
- Yaks::Format::CollectionJson,
22
- Yaks::Format::Hal,
23
- Yaks::Format::Halo,
24
- Yaks::Format::JsonAPI,
25
- Yaks::Mapper::AssociationMapper,
26
- Yaks::Mapper::Attribute,
27
- Yaks::Mapper::Config,
28
- Yaks::Mapper::HasOne,
29
- Yaks::Primitivize,
30
- Yaks::Resource,
31
- Yaks::Resource::Link,
32
- Yaks::Util,
33
- Yaks::Serializer,
34
- Yaks::Runner,
35
- Yaks::Mapper::Link,
36
- Yaks::Mapper::HasMany,
37
- Yaks::Mapper::ClassMethods,
38
- Yaks::Mapper::Association,
39
- Yaks::Mapper,
40
- Yaks::Format::HTML,
41
- Yaks::Mapper::Control,
42
- Yaks::Mapper::Control::Field,
43
- # Yaks::Resource::Control, #no subjects to mutate
44
- Yaks::NullResource,
38
+ # Yaks::Resource::Form, # no explicit coverage
39
+ # Yaks::Resource::Form::Field, # no explicit coverage
40
+ # Yaks::Mapper::Form::Field::Option, # no explicit coverage
41
+ # Yaks::Format::HTML, # no explicit coverage
42
+ Yaks::Runner, # 56/509 # 89.55%
43
+ Yaks::Resource, # 35/206 # 83.01%
44
+ Yaks::StatefulBuilder, # 25/192 # 86.98%
45
+ Yaks::Format::Halo, # 24/232 # 89.66%
46
+ Yaks::Mapper, # 15/482 # 96.89%
47
+ Yaks::Resource::Link, # 13/43 # 69.77%
48
+ Yaks::Mapper::Form::Field, # 11/155 # 92.90%
49
+ Yaks::Mapper::Link, # 10/357 # 97.20%
50
+ Yaks::CollectionMapper, # 7/217 # 96.77%
51
+ Yaks::Primitivize, # 3/239 # 98.74%
52
+ Yaks::Mapper::Form, # 3/179 # 98.32%
53
+ Yaks::CollectionResource, # 3/9 # 66.67%
54
+ Yaks::Format::JsonAPI, # 3/435 # 99.31%
55
+ Yaks::Format, # 2/29 # 93.10%
56
+ Yaks::Attributes, # 1/239 # 99.57%
57
+ Yaks::StatefulBuilder::StatefulMethods, # 1/66 # 98.49%
58
+ Yaks::Mapper::Association, # 1/222 # 99.55%
59
+ Yaks::Serializer, # 1/74 # 98.65%
60
+ Yaks::Format::Hal, # 1/328 # 99.70%
61
+ # Yaks::Format::Transit, # no explicit coverage
62
+ # Yaks::Format::Transit::WriteHandler, # no explicit coverage
63
+ # Yaks::Format::Transit::ReadHandler, # no explicit coverage
45
64
  ].each do |space|
46
65
  puts space
47
66
  ENV['PATTERN'] = "#{space}"
48
67
  Rake::Task["mutant"].execute
68
+ break
49
69
  end
50
70
  end
data/lib/yaks.rb CHANGED
@@ -36,10 +36,8 @@ module Yaks
36
36
  Yaks::Config.new(&blk)
37
37
  end
38
38
  end
39
-
40
39
  end
41
40
 
42
-
43
41
  require 'yaks/resource'
44
42
  require 'yaks/null_resource'
45
43
  require 'yaks/resource/link'
@@ -52,14 +50,15 @@ require 'yaks/mapper/has_one'
52
50
  require 'yaks/mapper/has_many'
53
51
  require 'yaks/mapper/attribute'
54
52
  require 'yaks/mapper/link'
55
- require 'yaks/mapper/control'
53
+ require 'yaks/mapper/form'
54
+ require 'yaks/mapper/form/field'
56
55
  require 'yaks/mapper/config'
57
56
  require 'yaks/mapper/class_methods'
58
57
  require 'yaks/mapper'
59
58
  require 'yaks/mapper/association_mapper'
60
59
  require 'yaks/collection_mapper'
61
60
 
62
- require 'yaks/resource/control'
61
+ require 'yaks/resource/form'
63
62
 
64
63
  require 'yaks/serializer'
65
64
 
@@ -1,24 +1,24 @@
1
1
  module Yaks
2
2
  class Attributes < Module
3
- attr_reader :defaults, :attributes
3
+ attr_reader :defaults, :names
4
4
 
5
5
  def initialize(*attrs)
6
6
  @defaults = attrs.last.instance_of?(Hash) ? attrs.pop : {}
7
- @attributes = (attrs + @defaults.keys).uniq
7
+ @names = (attrs + @defaults.keys).uniq
8
8
  end
9
9
 
10
10
  def add(*attrs)
11
11
  defaults = attrs.last.instance_of?(Hash) ? attrs.pop : {}
12
- self.class.new(*[*(attributes+attrs), @defaults.merge(defaults)])
12
+ self.class.new(*[*(names+attrs), @defaults.merge(defaults)])
13
13
  end
14
14
 
15
15
  def included(descendant)
16
16
  descendant.module_exec(self) do |this|
17
17
  include InstanceMethods,
18
- Anima.new(*this.attributes),
18
+ Anima.new(*this.names),
19
19
  Anima::Update
20
20
 
21
- this.attributes.each do |attr|
21
+ this.names.each do |attr|
22
22
  define_method attr do |value = Undefined|
23
23
  if value.equal? Undefined
24
24
  instance_variable_get("@#{attr}")
@@ -45,12 +45,16 @@ module Yaks
45
45
  indent = ->(str) { str.lines.map {|l| " #{l}"}.join }
46
46
  format = ->(val) { val.respond_to?(:pp) ? val.pp : val.inspect }
47
47
 
48
- fmt_attrs = self.class.attributes.attributes.map do |attr|
49
- value = public_send(attr)
48
+ defaults = self.class.attributes.defaults
49
+ values = to_h.reject do |attr, value|
50
+ value.equal?(defaults[attr])
51
+ end
52
+
53
+ fmt_attrs = values.map do |attr, value|
50
54
  fmt_val = case value
51
55
  when Array
52
56
  if value.inspect.length < 50
53
- value.inspect
57
+ "[#{value.map(&format).join(", ")}]"
54
58
  else
55
59
  "[\n#{indent[value.map(&format).join(",\n")]}\n]"
56
60
  end
@@ -58,9 +62,18 @@ module Yaks
58
62
  format[value]
59
63
  end
60
64
  "#{attr}: #{fmt_val}"
61
- end.join(",\n")
65
+ end
66
+
67
+ fmt_attrs_str = fmt_attrs.join(", ")
62
68
 
63
- "#{self.class.name}.new(\n#{indent[fmt_attrs]}\n)"
69
+ if fmt_attrs_str.length > 50
70
+ fmt_attrs_str = fmt_attrs.join(",\n")
71
+ end
72
+
73
+ if fmt_attrs_str =~ /\n/
74
+ fmt_attrs_str = "\n#{indent[fmt_attrs_str]}\n"
75
+ end
76
+ "#{self.class.name}.new(#{fmt_attrs_str})"
64
77
  end
65
78
  end
66
79
  end
data/lib/yaks/config.rb CHANGED
@@ -65,5 +65,9 @@ module Yaks
65
65
  runner(object, options).call
66
66
  end
67
67
  alias serialize call
68
+
69
+ def map(object, options = {})
70
+ runner(object, options).map(object)
71
+ end
68
72
  end
69
73
  end
@@ -1,27 +1,22 @@
1
1
  module Yaks
2
2
  module Configurable
3
- def self.included(descendant)
4
- descendant.instance_eval do
5
- extend ClassMethods
6
- end
7
- end
3
+ def config_method(name, options)
4
+ define_method name do |*args, &block|
5
+ defaults = options.fetch(:defaults, {})
6
+ klass = options.fetch(:create)
7
+
8
+ instance = if args.length.equal?(1) && args.first.instance_of?(klass)
9
+ args.first
10
+ else
11
+ if args.last.instance_of?(Hash)
12
+ args[-1] = defaults.merge(args[-1])
13
+ else
14
+ args << defaults
15
+ end
16
+ klass.create(*args, &block)
17
+ end
8
18
 
9
- module ClassMethods
10
- def config_method(name, options)
11
- define_method name do |*args, &block|
12
- defaults = options[:defaults]
13
- if defaults
14
- if args.last.is_a? Hash
15
- args[-1] = defaults.merge(args[-1])
16
- else
17
- args << defaults
18
- end
19
- end
20
- append_to(
21
- options.fetch(:append_to),
22
- options.fetch(:create).create(*args, &block)
23
- )
24
- end
19
+ append_to(options.fetch(:append_to), instance)
25
20
  end
26
21
  end
27
22
  end
data/lib/yaks/format.rb CHANGED
@@ -20,7 +20,7 @@ module Yaks
20
20
 
21
21
  # @param [Yaks::Resource] resource
22
22
  # @return [Hash]
23
- def call(resource, env = {})
23
+ def call(resource, _env = {})
24
24
  serialize_resource(resource)
25
25
  end
26
26
  alias serialize call
@@ -13,6 +13,7 @@ module Yaks
13
13
  items: serialize_items(resource)
14
14
  }
15
15
  result[:href] = resource.self_link.uri if resource.self_link
16
+ result[:links] = serialize_links(resource) if resource.collection? && resource.links.any?
16
17
  {collection: result}
17
18
  end
18
19
 
@@ -37,6 +38,14 @@ module Yaks
37
38
  result
38
39
  end
39
40
  end
41
+
42
+ def serialize_links(resource)
43
+ result = []
44
+ resource.links.each do |link|
45
+ result << {href: link.uri, rel: link.rel}
46
+ end
47
+ result
48
+ end
40
49
  end
41
50
  end
42
51
  end
@@ -8,28 +8,31 @@ module Yaks
8
8
  register :halo, :json, 'application/halo+json'
9
9
 
10
10
  def serialize_resource(resource)
11
- if resource.controls.any?
12
- super.merge(_controls: serialize_controls(resource.controls))
11
+ if resource.forms.any?
12
+ super.merge(_controls: serialize_forms(resource.forms))
13
13
  else
14
14
  super
15
15
  end
16
16
  end
17
17
 
18
- def serialize_controls(controls)
19
- controls.each_with_object({}) do |control, result|
20
- result[control.name] = serialize_control(control)
18
+ def serialize_forms(forms)
19
+ forms.each_with_object({}) do |form, result|
20
+ result[form.name] = serialize_form(form)
21
21
  end
22
22
  end
23
23
 
24
- def serialize_control(control)
25
- raw = control.to_h
24
+ def serialize_form(form)
25
+ raw = form.to_h
26
26
  raw[:href] = raw.delete(:action)
27
- raw[:fields] = control.fields.map(&:to_h)
28
- raw[:fields].each do |field|
29
- if field[:options].empty?
30
- field.delete(:options)
31
- else
32
- field[:options] || field[:options].map(&:to_h)
27
+ raw[:fields] = form.fields.map do |field|
28
+ field.to_h.each_with_object({}) do |(attr,value), hsh|
29
+ if attr == :options
30
+ if !value.empty?
31
+ hsh[:options] = value.map(&:to_h)
32
+ end
33
+ elsif HTML5Forms::FIELD_OPTIONS[attr] != value
34
+ hsh[attr] = value
35
+ end
33
36
  end
34
37
  end
35
38
  raw
@@ -28,8 +28,29 @@ module Yaks
28
28
  :url,
29
29
  :week,
30
30
 
31
- :select
31
+ :select,
32
+ :textarea,
33
+ :datalist
32
34
  ]
33
35
 
36
+ FIELD_OPTIONS = {
37
+ required: false,
38
+ rows: nil,
39
+ type: nil,
40
+ value: nil,
41
+ pattern: nil,
42
+ maxlength: nil,
43
+ minlength: 0,
44
+ size: 20,
45
+ readonly: false,
46
+ multiple: false,
47
+ min: nil,
48
+ max: nil,
49
+ step: nil,
50
+ list: nil,
51
+ placeholder: nil,
52
+ checked: false
53
+ }
54
+
34
55
  end
35
56
  end
data/lib/yaks/mapper.rb CHANGED
@@ -6,7 +6,7 @@ module Yaks
6
6
  include Util, FP, FP::Callable
7
7
 
8
8
  def_delegators 'self.class', :config
9
- def_delegators :config, :attributes, :links, :associations, :controls
9
+ def_delegators :config, :attributes, :links, :associations, :forms
10
10
 
11
11
  config Config.new
12
12
 
@@ -44,7 +44,7 @@ module Yaks
44
44
  [ :map_attributes,
45
45
  :map_links,
46
46
  :map_subresources,
47
- :map_controls
47
+ :map_forms
48
48
  ].inject(Resource.new(type: mapper_name)) do |resource, method|
49
49
  send(method, resource)
50
50
  end
@@ -100,9 +100,9 @@ module Yaks
100
100
  end
101
101
  end
102
102
 
103
- def map_controls(resource)
104
- controls.inject(resource) do |res, control|
105
- control.add_to_resource(res, self, context)
103
+ def map_forms(resource)
104
+ forms.inject(resource) do |res, form|
105
+ form.add_to_resource(res, self, context)
106
106
  end
107
107
  end
108
108
  end
@@ -1,7 +1,7 @@
1
1
  module Yaks
2
2
  class Mapper
3
3
  class Attribute
4
- include Concord::Public.new(:name)
4
+ include Attributes.new(:name)
5
5
 
6
6
  def initialize(name)
7
7
  @name = name