yaks 0.7.6 → 0.7.7

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