yaks 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 45ba297e354c237fe7dac7c3570c9405b1235c03
4
- data.tar.gz: b8d1873f4e2bb1b4103608a48660a13a970babf0
3
+ metadata.gz: 3eb709b078f05c15a877f6c3008df313d09e2bbe
4
+ data.tar.gz: cd8d14498bbf3c74b2362b66c30dee5ec00d3c53
5
5
  SHA512:
6
- metadata.gz: 44d29bbb7d61bb15939d6b8d14ee7267d95c6c52003fdd560d3046a7484d344b3e1c7b0fb0ba4bb220bb06475b78305033506e9192da7c4f3df0f74a7665e654
7
- data.tar.gz: 9b5c263fa66d6c519087164de7b1c0d6d626dc99b221efcc83ca103361e983b474e1116472ebc5af620fb7471d2d294a892754f775948a9549e0ebbaafe55a19
6
+ metadata.gz: 4cc2b5d05868b2869684481a6a9a37d513b66da63dfe995307b1c2c933ab349bf0bf200f5342e60ef485f756046e2308854227f895ec1b302ed4ec0b91f1d6c8
7
+ data.tar.gz: cde85afd3d63e33420ebe61e24638f1d00ceb26f93db91f48f19f42f7de531d4cd84e17dc7e74586a95afd5369d22293b4431f2208073a2ac48d84788bb67526
@@ -40,6 +40,28 @@ module Yaks
40
40
  def append_to(type, *objects)
41
41
  update(type => instance_variable_get("@#{type}") + objects)
42
42
  end
43
+
44
+ def pp
45
+ indent = ->(str) { str.lines.map {|l| " #{l}"}.join }
46
+ format = ->(val) { val.respond_to?(:pp) ? val.pp : val.inspect }
47
+
48
+ fmt_attrs = self.class.attributes.attributes.map do |attr|
49
+ value = public_send(attr)
50
+ fmt_val = case value
51
+ when Array
52
+ if value.inspect.length < 50
53
+ value.inspect
54
+ else
55
+ "[\n#{indent[value.map(&format).join(",\n")]}\n]"
56
+ end
57
+ else
58
+ format[value]
59
+ end
60
+ "#{attr}: #{fmt_val}"
61
+ end.join(",\n")
62
+
63
+ "#{self.class.name}.new(\n#{indent[fmt_attrs]}\n)"
64
+ end
43
65
  end
44
66
  end
45
67
  end
@@ -5,6 +5,28 @@ module Yaks
5
5
 
6
6
  BreakingChanges = {
7
7
 
8
+ '0.7.6' => %q~
9
+ Breaking Changes in Yaks 0.7.6
10
+ ==============================
11
+ Breaking change: using a symbol instead of link template no longer
12
+ works, use a lambda.
13
+
14
+ link :foo, :bar
15
+
16
+ Becomes
17
+
18
+ link :foo, ->{ bar }
19
+
20
+ Strictly speaking the equivalent version would be `link :foo, ->{
21
+ load_attribute(:bar) }`. Depending on if `bar` is implemented on the
22
+ mapper or is an attribute of the object, this would simplify to `link
23
+ :foo, ->{ bar }` or `link :foo, ->{ object.bar }` respectively.
24
+
25
+ The `href` attribute of a control has been renamed `action`, in line
26
+ with the attribute name in HTML. An alias is available but will output
27
+ a deprecation warning.
28
+ ~,
29
+
8
30
  '0.7.0' => %q~
9
31
  Breaking Changes in Yaks 0.7.0
10
32
  ==============================
@@ -0,0 +1,21 @@
1
+ module Yaks
2
+ module Changelog
3
+ extend self
4
+
5
+ def current
6
+ versions[Yaks::VERSION]
7
+ end
8
+
9
+ def versions
10
+ markdown.split(/(?=###\s*[\d\.]+\n)/).each_with_object({}) do |section, hsh|
11
+ version = section.each_line.first[/[\d\.]+/]
12
+ log = section.each_line.drop(1).join.strip
13
+ hsh[version] = log
14
+ end
15
+ end
16
+
17
+ def markdown
18
+ Pathname(__FILE__).join('../../../../CHANGELOG.md').read
19
+ end
20
+ end
21
+ end
@@ -9,6 +9,14 @@ module Yaks
9
9
  module ClassMethods
10
10
  def config_method(name, options)
11
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
12
20
  append_to(
13
21
  options.fetch(:append_to),
14
22
  options.fetch(:create).create(*args, &block)
@@ -22,7 +22,17 @@ module Yaks
22
22
  end
23
23
 
24
24
  def serialize_control(control)
25
- control.to_h.merge(fields: control.fields.map(&:to_h))
25
+ raw = control.to_h
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)
33
+ end
34
+ end
35
+ raw
26
36
  end
27
37
  end
28
38
  end
@@ -0,0 +1,35 @@
1
+ module Yaks
2
+ # Based on the HTML living standard over at WHATWG
3
+ # https://html.spec.whatwg.org/multipage/forms.html
4
+ #
5
+ # Does not aim to be complete, does aim to be a strict subset.
6
+ module HTML5Forms
7
+
8
+ INPUT_TYPES = [
9
+ :checkbox,
10
+ :color,
11
+ :date,
12
+ :datetime,
13
+ :datetime_local, # :datetime-local in the spec
14
+ :email,
15
+ :file,
16
+ :hidden,
17
+ :image,
18
+ :month,
19
+ :number,
20
+ :password,
21
+ :radio,
22
+ :range,
23
+ :reset,
24
+ :search,
25
+ :tel,
26
+ :text,
27
+ :time,
28
+ :url,
29
+ :week,
30
+
31
+ :select
32
+ ]
33
+
34
+ end
35
+ end
@@ -22,8 +22,13 @@ module Yaks
22
22
  config_method :attribute, create: Attribute, append_to: :attributes
23
23
  config_method :attribute, create: Attribute, append_to: :attributes
24
24
  config_method :control,
25
- create: StatefulBuilder.new(Control, Control.anima.attribute_names + [:field]),
26
- append_to: :controls
25
+ append_to: :controls,
26
+ create: StatefulBuilder.new(
27
+ Control,
28
+ Control.anima.attribute_names +
29
+ HTML5Forms::INPUT_TYPES +
30
+ [:field]
31
+ )
27
32
  end
28
33
  end
29
34
  end
@@ -1,35 +1,43 @@
1
1
  module Yaks
2
2
  class Mapper
3
3
  class Control
4
+ extend Util::Deprecated
4
5
  include Attributes.new(
5
- name: nil, href: nil, title: nil, method: nil, media_type: nil, fields: []
6
+ name: nil, action: nil, title: nil, method: nil, media_type: nil, fields: []
6
7
  ),
7
8
  Configurable
8
9
 
10
+ alias enctype media_type
11
+ deprecated_alias :href, :action
12
+
9
13
  def self.create(name = nil, options = {})
10
14
  new({name: name}.merge(options))
11
15
  end
12
16
 
13
- def add_to_resource(resource, parent_mapper, _context)
14
- resource.add_control(map_to_resource_control(resource, parent_mapper))
17
+ def add_to_resource(resource, mapper, _context)
18
+ resource.add_control(to_resource(mapper))
15
19
  end
16
20
 
17
- def map_to_resource_control(resource, parent_mapper)
21
+ def to_resource(mapper)
18
22
  attrs = {
19
- fields: resource_fields,
20
- href: parent_mapper.expand_uri(href, true)
23
+ fields: resource_fields(mapper),
24
+ action: mapper.expand_uri(action, true)
21
25
  }
22
- Resource::Control.new(to_h.merge(attrs))
26
+ [:name, :title, :method, :media_type].each do |attr|
27
+ attrs[attr] = mapper.expand_value(public_send(attr))
28
+ end
29
+ Resource::Control.new(attrs)
23
30
  end
24
31
 
25
- def resource_fields
26
- fields.map(&:to_resource_field)
32
+ def resource_fields(mapper)
33
+ fields.map { |field| field.to_resource(mapper) }
27
34
  end
28
35
 
29
36
  class Field
30
- include Attributes.new(:name, label: nil, type: "text", value: nil)
37
+ include Attributes.new(:name, label: nil, type: "text", value: nil, options: []),
38
+ Configurable
31
39
 
32
- def self.create(*args)
40
+ def self.create(*args, &block)
33
41
  attrs = args.last.instance_of?(Hash) ? args.pop : {}
34
42
  if name = args.shift
35
43
  attrs = attrs.merge(name: name)
@@ -37,12 +45,38 @@ module Yaks
37
45
  new(attrs)
38
46
  end
39
47
 
40
- def to_resource_field
41
- Resource::Control::Field.new(to_h)
48
+ def to_resource(mapper)
49
+ Resource::Control::Field.new(
50
+ [:name, :label, :type, :value].each_with_object({}) do |attr, attrs|
51
+ attrs[attr] = mapper.expand_value(public_send(attr))
52
+ end.merge(options: options.map(&:to_resource))
53
+ )
54
+ end
55
+
56
+ class Option
57
+ include Attributes.new(:value, :label, selected: false)
58
+
59
+ def self.create(value, opts = {})
60
+ new(opts.merge(value: value))
61
+ end
62
+
63
+ def to_resource
64
+ to_h #placeholder
65
+ end
42
66
  end
67
+
68
+ config_method :option,
69
+ append_to: :options,
70
+ create: Option
43
71
  end
44
72
 
45
- config_method :field, create: Field, append_to: :fields
73
+ FieldBuilder = StatefulBuilder.new(Field, [:name, :label, :type, :value, :option])
74
+
75
+ config_method :field, create: FieldBuilder, append_to: :fields
76
+
77
+ HTML5Forms::INPUT_TYPES.each do |type|
78
+ config_method type, create: FieldBuilder, append_to: :fields, defaults: { type: type }
79
+ end
46
80
  end
47
81
  end
48
82
  end
data/lib/yaks/mapper.rb CHANGED
@@ -55,15 +55,13 @@ module Yaks
55
55
  end
56
56
  alias load_association load_attribute
57
57
 
58
+ def expand_value(value)
59
+ Resolve(value, self)
60
+ end
61
+
58
62
  def expand_uri(uri, expand)
59
- case uri
60
- when nil
61
- return
62
- when Symbol
63
- return load_attribute(uri)
64
- when Method, Proc
65
- return Resolve(uri, self)
66
- end
63
+ return if uri.nil?
64
+ return Resolve(uri, self) if uri.respond_to?(:to_proc)
67
65
 
68
66
  template = URITemplate.new(uri)
69
67
  expand_vars = case expand
data/lib/yaks/resource.rb CHANGED
@@ -64,26 +64,5 @@ module Yaks
64
64
  append_to(:subresources, subresource)
65
65
  end
66
66
 
67
- def pp
68
- indent = ->(str) { str.lines.map {|l| " #{l}"}.join }
69
- format = ->(val) { val.respond_to?(:pp) ? val.pp : val.inspect }
70
-
71
- fmt_attrs = self.class.attributes.attributes.map do |attr|
72
- value = public_send(attr)
73
- fmt_val = case value
74
- when Array
75
- if value.inspect.length < 50
76
- value.inspect
77
- else
78
- "[\n#{indent[value.map(&format).join(",\n")]}\n]"
79
- end
80
- else
81
- format[value]
82
- end
83
- "#{attr}=#{fmt_val}"
84
- end.join("\n")
85
-
86
- "#<#{self.class.name}\n#{indent[fmt_attrs]}\n>"
87
- end
88
67
  end
89
68
  end
@@ -8,23 +8,24 @@ module Yaks
8
8
  # # This code
9
9
  # Control.create(:search)
10
10
  # .method("POST")
11
- # .href("/search")
11
+ # .action("/search")
12
12
  #
13
13
  # # Can be written as
14
- # StatefulBuilder.new(Control, [:method, :href]).create(:search) do
14
+ # StatefulBuilder.new(Control, [:method, :action]).create(:search) do
15
15
  # method "POST"
16
- # href "/search"
16
+ # action "/search"
17
17
  # end
18
18
  #
19
19
  class StatefulBuilder < BasicObject
20
20
  def create(*args, &block)
21
21
  @state = @klass.create(*args)
22
- instance_eval(&block)
22
+ instance_eval(&block) if block
23
23
  @state
24
24
  end
25
25
 
26
26
  def initialize(klass, methods)
27
27
  @klass = klass
28
+ @methods = methods
28
29
  StatefulMethods.new(methods).send(:extend_object, self)
29
30
  end
30
31
 
@@ -38,6 +39,10 @@ module Yaks
38
39
  end
39
40
  end
40
41
 
42
+ def inspect
43
+ "#<#{self.class} #{@klass} #{@methods.inspect}>"
44
+ end
45
+
41
46
  class StatefulMethods < ::Module
42
47
  def initialize(methods)
43
48
  methods.each { |name| define_stateful_method(name) }
data/lib/yaks/util.rb CHANGED
@@ -36,7 +36,7 @@ module Yaks
36
36
  # @param [Object] context
37
37
  # (optional) A context used to instance_eval the proc
38
38
  def Resolve(maybe_proc, context = nil)
39
- if maybe_proc.is_a? Proc or maybe_proc.is_a? Method
39
+ if maybe_proc.respond_to?(:to_proc) && !maybe_proc.instance_of?(Symbol)
40
40
  if context
41
41
  if maybe_proc.arity > 0
42
42
  context.instance_eval(&maybe_proc)
@@ -45,12 +45,21 @@ module Yaks
45
45
  context.instance_exec(&maybe_proc)
46
46
  end
47
47
  else
48
- maybe_proc.()
48
+ maybe_proc.to_proc.()
49
49
  end
50
50
  else
51
51
  maybe_proc
52
52
  end
53
53
  end
54
54
 
55
+ module Deprecated
56
+ def deprecated_alias(name, actual)
57
+ define_method name do |*args, &block|
58
+ $stderr.puts "WARNING: #{self.class}##{name} is deprecated, use `#{actual}'. at #{caller.first}"
59
+ send(actual, *args, &block)
60
+ end
61
+ end
62
+ end
63
+
55
64
  end
56
65
  end
data/lib/yaks/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yaks
2
- VERSION = '0.7.5'
2
+ VERSION = '0.7.6'
3
3
  end
data/lib/yaks.rb CHANGED
@@ -11,6 +11,7 @@ require 'inflection'
11
11
  require 'uri_template'
12
12
  require 'rack/accept'
13
13
 
14
+ require 'yaks/version'
14
15
  require 'yaks/util'
15
16
  require 'yaks/configurable'
16
17
  require 'yaks/fp'
@@ -44,6 +45,8 @@ require 'yaks/null_resource'
44
45
  require 'yaks/resource/link'
45
46
  require 'yaks/collection_resource'
46
47
 
48
+ require 'yaks/html5_forms'
49
+
47
50
  require 'yaks/mapper/association'
48
51
  require 'yaks/mapper/has_one'
49
52
  require 'yaks/mapper/has_many'
@@ -15,8 +15,8 @@ RSpec.describe Yaks::Format::JsonAPI do
15
15
  end
16
16
 
17
17
  context 'with both a "href" attribute and a self link' do
18
- let(:resource) {
19
- Yaks::Resource.new(
18
+ let(:resource) {
19
+ Yaks::Resource.new(
20
20
  type: 'wizard',
21
21
  attributes: {
22
22
  href: '/the/href'
@@ -27,6 +27,7 @@ RSpec.describe Yaks::Format::JsonAPI do
27
27
  )
28
28
  }
29
29
 
30
+ # TODO should it really behave this way? better to give preference to self link.
30
31
  it 'should give preference to the href attribute' do
31
32
  expect(format.call(resource)).to eql(
32
33
  {'wizards' => [
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Yaks::Mapper::Control::Field do
4
+ include_context 'yaks context'
5
+
4
6
  let(:field) { described_class.new( full_args ) }
5
7
  let(:name) { :the_field }
6
8
  let(:full_args) { {name: name}.merge(args) }
@@ -12,6 +14,8 @@ RSpec.describe Yaks::Mapper::Control::Field do
12
14
  }
13
15
  }
14
16
 
17
+ let(:mapper) { Yaks::Mapper.new(yaks_context) }
18
+
15
19
  describe '.create' do
16
20
  it 'can take all args as a hash' do
17
21
  expect(described_class.create(full_args)).to eql described_class.new(full_args)
@@ -28,7 +32,7 @@ RSpec.describe Yaks::Mapper::Control::Field do
28
32
 
29
33
  describe '#to_resource_field' do
30
34
  it 'creates a Yaks::Resource::Control::Field with the same attributes' do
31
- expect(field.to_resource_field).to eql Yaks::Resource::Control::Field.new(full_args)
35
+ expect(field.to_resource(mapper)).to eql Yaks::Resource::Control::Field.new(full_args)
32
36
  end
33
37
  end
34
38
  end
@@ -6,7 +6,7 @@ RSpec.describe Yaks::Mapper::Control do
6
6
  let(:full_args) { {name: name}.merge(args) }
7
7
  let(:args) {
8
8
  {
9
- href: '/foo',
9
+ action: '/foo',
10
10
  title: 'a title',
11
11
  method: 'PATCH',
12
12
  media_type: 'application/hal+json',
@@ -31,7 +31,7 @@ RSpec.describe Yaks::Mapper::Link do
31
31
  end
32
32
 
33
33
  context 'with a link function returning nothing' do
34
- let(:template) { :link_computer }
34
+ let(:template) { ->{ link_computer } }
35
35
  before do
36
36
  mapper_class.class_eval do
37
37
  def link_computer ; end
@@ -157,7 +157,7 @@ RSpec.describe Yaks::Mapper::Link do
157
157
  end
158
158
 
159
159
  context 'with a link generation method that returns nil' do
160
- let(:template) { :returns_nil }
160
+ let(:template) { ->{ object.returns_nil } }
161
161
 
162
162
  it 'should return nil' do
163
163
  expect(resource_link).to be_nil
@@ -187,7 +187,7 @@ RSpec.describe Yaks::Mapper do
187
187
  before do
188
188
  mapper_class.class_eval do
189
189
  attributes :id
190
- link :bar_link, :link_generating_method
190
+ link :bar_link, -> { link_generating_method }
191
191
 
192
192
  def link_generating_method
193
193
  end
@@ -365,7 +365,7 @@ RSpec.describe Yaks::Mapper do
365
365
  end
366
366
 
367
367
  context 'with a symbol for a template' do
368
- let(:template) { :foo }
368
+ let(:template) { -> { object.foo } }
369
369
 
370
370
  it 'should use the lookup mechanism for finding the link' do
371
371
  expect(expanded).to eq '/foo/foo'
data/yaks.gemspec CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require File.expand_path('../lib/yaks/version', __FILE__)
4
4
  require File.expand_path('../lib/yaks/breaking_changes', __FILE__)
5
+ require File.expand_path('../lib/yaks/changelog', __FILE__)
5
6
 
6
7
  Gem::Specification.new do |gem|
7
8
  gem.name = 'yaks'
@@ -18,6 +19,8 @@ Gem::Specification.new do |gem|
18
19
  gem.test_files = gem.files.grep(/^spec/)
19
20
  gem.extra_rdoc_files = %w[README.md]
20
21
 
22
+ gem.metadata = {'changelog' => Yaks::Changelog.current[0...1000]}
23
+
21
24
  if Yaks::BreakingChanges.key? Yaks::VERSION
22
25
  gem.post_install_message = Yaks::BreakingChanges[Yaks::VERSION]
23
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yaks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.5
4
+ version: 0.7.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arne Brasseur
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-17 00:00:00.000000000 Z
11
+ date: 2014-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inflection
@@ -247,6 +247,7 @@ files:
247
247
  - lib/yaks.rb
248
248
  - lib/yaks/attributes.rb
249
249
  - lib/yaks/breaking_changes.rb
250
+ - lib/yaks/changelog.rb
250
251
  - lib/yaks/collection_mapper.rb
251
252
  - lib/yaks/collection_resource.rb
252
253
  - lib/yaks/config.rb
@@ -261,6 +262,7 @@ files:
261
262
  - lib/yaks/format/json_api.rb
262
263
  - lib/yaks/fp.rb
263
264
  - lib/yaks/fp/callable.rb
265
+ - lib/yaks/html5_forms.rb
264
266
  - lib/yaks/mapper.rb
265
267
  - lib/yaks/mapper/association.rb
266
268
  - lib/yaks/mapper/association_mapper.rb
@@ -345,8 +347,62 @@ files:
345
347
  homepage: https://github.com/plexus/yaks
346
348
  licenses:
347
349
  - MIT
348
- metadata: {}
349
- post_install_message:
350
+ metadata:
351
+ changelog: |-
352
+ Much expanded form support, simplified link DSL, pretty-print objects
353
+ to Ruby code.
354
+
355
+ Breaking change: using a symbol instead of link template no longer
356
+ works, use a lambda.
357
+
358
+ link :foo, :bar
359
+
360
+ Becomes
361
+
362
+ link :foo, ->{ bar }
363
+
364
+ Strictly speaking the equivalent version would be `link :foo, ->{
365
+ load_attribute(:bar) }`. Depending on if `bar` is implemented on the
366
+ mapper or is an attribute of the object, this would simplify to `link
367
+ :foo, ->{ bar }` or `link :foo, ->{ object.bar }` respectively.
368
+
369
+ The form control DSL has been expanded, instead of `field type:
370
+ 'text'` and similar there are now aliases, e.g. `text :name, value:
371
+ 'foo'`.
372
+
373
+ All attributes on the form control itself, and on fields, now
374
+ optionally take a lambda (any `#to_proc`-able) for dynamic
375
+ content. e.g.
376
+
377
+ control :add_product do
378
+ method 'POST'
379
+ action ->{ '/cart/#{cart.id}/line_items' }
380
+ hidden :product_id, value: -> { product.id }
381
+ number :quantity, value: 0
382
+ end
383
+
384
+ As with lambdas used for links, i
385
+ post_install_message: |2
386
+
387
+ Breaking Changes in Yaks 0.7.6
388
+ ==============================
389
+ Breaking change: using a symbol instead of link template no longer
390
+ works, use a lambda.
391
+
392
+ link :foo, :bar
393
+
394
+ Becomes
395
+
396
+ link :foo, ->{ bar }
397
+
398
+ Strictly speaking the equivalent version would be `link :foo, ->{
399
+ load_attribute(:bar) }`. Depending on if `bar` is implemented on the
400
+ mapper or is an attribute of the object, this would simplify to `link
401
+ :foo, ->{ bar }` or `link :foo, ->{ object.bar }` respectively.
402
+
403
+ The `href` attribute of a control has been renamed `action`, in line
404
+ with the attribute name in HTML. An alias is available but will output
405
+ a deprecation warning.
350
406
  rdoc_options: []
351
407
  require_paths:
352
408
  - lib