praxis 0.21 → 2.0.pre.3

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +8 -15
  3. data/CHANGELOG.md +328 -299
  4. data/CONTRIBUTING.md +4 -4
  5. data/README.md +11 -9
  6. data/lib/api_browser/app/js/directives/attribute_table.js +2 -1
  7. data/lib/api_browser/app/js/directives/conditional_requirements.js +13 -0
  8. data/lib/api_browser/app/js/directives/type_placeholder.js +10 -1
  9. data/lib/api_browser/app/js/factories/normalize_attributes.js +4 -2
  10. data/lib/api_browser/app/js/factories/template_for.js +5 -2
  11. data/lib/api_browser/app/js/filters/has_requirement.js +14 -0
  12. data/lib/api_browser/app/js/filters/tag_requirement.js +13 -0
  13. data/lib/api_browser/app/sass/praxis.scss +11 -0
  14. data/lib/api_browser/app/views/action.html +2 -2
  15. data/lib/api_browser/app/views/directives/attribute_description/member_options.html +2 -2
  16. data/lib/api_browser/app/views/directives/attribute_table.html +1 -1
  17. data/lib/api_browser/app/views/type.html +1 -1
  18. data/lib/api_browser/app/views/type/details.html +2 -2
  19. data/lib/api_browser/app/views/types/embedded/array.html +2 -0
  20. data/lib/api_browser/app/views/types/embedded/default.html +3 -1
  21. data/lib/api_browser/app/views/types/embedded/requirements.html +6 -0
  22. data/lib/api_browser/app/views/types/embedded/single_req.html +9 -0
  23. data/lib/api_browser/app/views/types/embedded/struct.html +14 -2
  24. data/lib/api_browser/app/views/types/standalone/array.html +1 -1
  25. data/lib/api_browser/app/views/types/standalone/struct.html +2 -1
  26. data/lib/api_browser/package.json +1 -1
  27. data/lib/praxis.rb +9 -3
  28. data/lib/praxis/action_definition.rb +1 -1
  29. data/lib/praxis/action_definition/headers_dsl_compiler.rb +1 -1
  30. data/lib/praxis/application.rb +1 -9
  31. data/lib/praxis/bootloader.rb +1 -4
  32. data/lib/praxis/config.rb +1 -1
  33. data/lib/praxis/dispatcher.rb +10 -6
  34. data/lib/praxis/docs/generator.rb +2 -1
  35. data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +180 -0
  36. data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +273 -0
  37. data/lib/praxis/extensions/attribute_filtering/sequel_filter_query_builder.rb +125 -0
  38. data/lib/praxis/extensions/field_selection.rb +1 -9
  39. data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +51 -0
  40. data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +61 -0
  41. data/lib/praxis/extensions/rails_compat.rb +2 -0
  42. data/lib/praxis/extensions/rails_compat/request_methods.rb +19 -0
  43. data/lib/praxis/handlers/xml.rb +1 -1
  44. data/lib/praxis/mapper/active_model_compat.rb +98 -0
  45. data/lib/praxis/mapper/resource.rb +242 -0
  46. data/lib/praxis/mapper/selector_generator.rb +149 -0
  47. data/lib/praxis/mapper/sequel_compat.rb +76 -0
  48. data/lib/praxis/media_type_identifier.rb +2 -1
  49. data/lib/praxis/middleware_app.rb +20 -2
  50. data/lib/praxis/multipart/parser.rb +14 -2
  51. data/lib/praxis/notifications.rb +1 -1
  52. data/lib/praxis/plugins/mapper_plugin.rb +64 -0
  53. data/lib/praxis/plugins/rails_plugin.rb +104 -0
  54. data/lib/praxis/request.rb +7 -1
  55. data/lib/praxis/request_superclassing.rb +11 -0
  56. data/lib/praxis/resource_definition.rb +5 -5
  57. data/lib/praxis/response.rb +1 -1
  58. data/lib/praxis/route.rb +1 -1
  59. data/lib/praxis/routing_config.rb +1 -1
  60. data/lib/praxis/trait.rb +1 -1
  61. data/lib/praxis/types/media_type_common.rb +2 -2
  62. data/lib/praxis/types/multipart.rb +1 -1
  63. data/lib/praxis/types/multipart_array.rb +2 -2
  64. data/lib/praxis/types/multipart_array/part_definition.rb +1 -1
  65. data/lib/praxis/version.rb +1 -1
  66. data/praxis.gemspec +14 -13
  67. data/spec/functional_spec.rb +4 -7
  68. data/spec/praxis/action_definition_spec.rb +1 -1
  69. data/spec/praxis/application_spec.rb +1 -1
  70. data/spec/praxis/collection_spec.rb +3 -2
  71. data/spec/praxis/config_spec.rb +2 -2
  72. data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +106 -0
  73. data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +147 -0
  74. data/spec/praxis/extensions/field_selection/support/spec_resources_active_model.rb +130 -0
  75. data/spec/praxis/extensions/field_selection/support/spec_resources_sequel.rb +106 -0
  76. data/spec/praxis/handlers/xml_spec.rb +2 -2
  77. data/spec/praxis/mapper/resource_spec.rb +169 -0
  78. data/spec/praxis/mapper/selector_generator_spec.rb +293 -0
  79. data/spec/praxis/media_type_spec.rb +0 -10
  80. data/spec/praxis/middleware_app_spec.rb +29 -9
  81. data/spec/praxis/request_stages/action_spec.rb +8 -1
  82. data/spec/praxis/response_definition_spec.rb +7 -4
  83. data/spec/praxis/response_spec.rb +1 -1
  84. data/spec/praxis/responses/internal_server_error_spec.rb +2 -2
  85. data/spec/praxis/responses/validation_error_spec.rb +2 -2
  86. data/spec/praxis/router_spec.rb +1 -1
  87. data/spec/spec_app/app/controllers/instances.rb +1 -1
  88. data/spec/spec_app/config/environment.rb +3 -21
  89. data/spec/spec_helper.rb +11 -15
  90. data/spec/support/be_deep_equal_matcher.rb +39 -0
  91. data/spec/support/spec_resources.rb +124 -0
  92. data/tasks/thor/templates/generator/empty_app/Gemfile +3 -3
  93. metadata +102 -77
  94. data/.ruby-version +0 -1
  95. data/lib/praxis/extensions/mapper_selectors.rb +0 -16
  96. data/lib/praxis/media_type_collection.rb +0 -127
  97. data/lib/praxis/plugins/praxis_mapper_plugin.rb +0 -246
  98. data/lib/praxis/stats.rb +0 -113
  99. data/spec/praxis/media_type_collection_spec.rb +0 -157
  100. data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +0 -142
  101. data/spec/praxis/stats_spec.rb +0 -9
  102. data/spec/spec_app/app/models/person.rb +0 -3
@@ -52,16 +52,6 @@ describe Praxis::MediaType do
52
52
  subject(:address_klass) { address.class }
53
53
 
54
54
  context '#identifier' do
55
- context 'in praxis v0' do
56
- it 'should be a kind of String' do
57
- if Praxis::VERSION =~ /^0/
58
- expect(subject.identifier).to be_kind_of(String)
59
- else
60
- raise 'Please remove this spec which is no longer pertinent'
61
- end
62
- end
63
- end
64
-
65
55
  context 'in praxis v1.0 and beyond' do
66
56
  it 'should be a kind of Praxis::MediaTypeIdentifier' do
67
57
  pending('interface-breaking change') if Praxis::VERSION =~ /^0/
@@ -2,35 +2,55 @@ require 'spec_helper'
2
2
 
3
3
  describe Praxis::MiddlewareApp do
4
4
 
5
- context '.for' do
6
- let(:init_args){ { root: 'here'} }
7
- subject(:middleware) { Praxis::MiddlewareApp.for( init_args ) }
5
+ let(:init_args){ { root: 'here'} }
6
+ let(:middleware) { Praxis::MiddlewareApp.for( **init_args ) }
7
+ let(:instance){ middleware.new(target)}
8
8
 
9
- it 'initializes the application singletone with the passed parameters' do
10
- expect( Praxis::Application.instance ).to receive(:setup).with( init_args ).once
11
- subject
9
+ context '.for' do
10
+ it 'does not initialize the Application instance yet' do
11
+ expect( Praxis::Application.instance ).to_not receive(:setup)
12
+ middleware
12
13
  end
13
14
  it 'returns its class' do
14
- expect( subject ).to be( Praxis::MiddlewareApp )
15
+ expect( middleware ).to be < Praxis::MiddlewareApp
15
16
  end
16
17
  end
17
18
 
18
19
  context 'instantiated' do
20
+ subject{ instance }
19
21
  let(:target_response){ [201,{}] }
20
22
  let(:target){ double("target app", call: target_response) }
21
- subject(:instance){ Praxis::MiddlewareApp.new(target)}
22
23
  it 'saves the target app' do
23
24
  expect(subject.target).to be(target)
24
25
  end
26
+ it 'does not initialize the Application instance yet' do
27
+ expect( Praxis::Application.instance ).to_not receive(:setup)
28
+ subject
29
+ end
30
+
25
31
  context '.call' do
26
32
  let(:env){ {} }
27
33
  let(:praxis_response){ [200,{}] }
28
- subject(:response){ Praxis::MiddlewareApp.new(target).call(env) }
34
+ subject(:response){ instance.call(env) }
29
35
  before do
30
36
  # always invokes the praxis app
31
37
  expect( Praxis::Application.instance ).to receive(:call).with( env ).once.and_return(praxis_response)
32
38
  end
33
39
 
40
+ context 'when it has not been setup yet' do
41
+ it 'initializes the application singleton with the passed parameters' do
42
+ expect( Praxis::Application.instance ).to receive(:setup).with( init_args ).once
43
+ subject
44
+ end
45
+ end
46
+ context 'when it has already been setup' do
47
+ it 'does NOT call instance setup' do
48
+ middleware.setup
49
+ expect( Praxis::Application.instance ).to_not receive(:setup)
50
+ subject
51
+ end
52
+ end
53
+
34
54
  context 'properly handled (non-404 and 405) responses from praxis' do
35
55
  it 'are returned straight through' do
36
56
  expect( response ).to be(praxis_response)
@@ -26,7 +26,14 @@ describe Praxis::RequestStages::Action do
26
26
 
27
27
  context '.execute' do
28
28
  before do
29
- expect(controller).to receive(action_stage.name).with(request.params_hash).and_return(controller_response)
29
+ expect(controller).to receive(action_stage.name) do |args|
30
+ if args
31
+ expect(args).to eq({})
32
+ else
33
+ expect(args).to eq(nil)
34
+ end
35
+ end.and_return(controller_response)
36
+
30
37
  end
31
38
  let(:controller_response){ controller.response }
32
39
 
@@ -448,7 +448,7 @@ describe Praxis::ResponseDefinition do
448
448
  context 'with legacy multipart response' do
449
449
  subject(:response) { Praxis::Responses::Ok.new(status: response_status, headers: response_headers) }
450
450
 
451
- let(:part) { Praxis::MultipartPart.new('done', {'Status' => 200, 'Content-Type' => 'application/special'},{}) }
451
+ let(:part) { Praxis::MultipartPart.new('done', {'Status' => 200, 'Content-Type' => 'application/special'},**{}) }
452
452
 
453
453
  before do
454
454
  response_definition.parts like: :ok, media_type: 'application/special'
@@ -463,7 +463,7 @@ describe Praxis::ResponseDefinition do
463
463
  end
464
464
 
465
465
  context 'with invalid part' do
466
- let(:part) { Praxis::MultipartPart.new('done', {'Status' => 200, "Location" => "somewhere"},{}) }
466
+ let(:part) { Praxis::MultipartPart.new('done', {'Status' => 200, "Location" => "somewhere"}) }
467
467
 
468
468
  it 'validates' do
469
469
  expect {
@@ -494,6 +494,7 @@ describe Praxis::ResponseDefinition do
494
494
  let(:location) { %r{/my/url/} }
495
495
  let(:headers) { {'Header1' => 'Value1'} }
496
496
  let(:parts) { nil }
497
+ let(:parts_block) { nil }
497
498
 
498
499
  let(:response) do
499
500
  Praxis::ResponseDefinition.new(:custom) do
@@ -505,7 +506,9 @@ describe Praxis::ResponseDefinition do
505
506
  before do
506
507
  response.description(description) if description
507
508
  response.location(location) if location
508
- response.parts(parts) if parts
509
+ if parts || parts_block
510
+ parts ? response.parts(nil, **parts, &parts_block) : response.parts(nil, &parts_block)
511
+ end
509
512
  response.headers(headers) if headers
510
513
  end
511
514
 
@@ -572,7 +575,7 @@ describe Praxis::ResponseDefinition do
572
575
  its([:status]){ should == 200 }
573
576
  end
574
577
  context 'using a full response definition block' do
575
- let(:parts) do
578
+ let(:parts_block) do
576
579
  Proc.new do
577
580
  status 234
578
581
  media_type 'custom_media'
@@ -117,7 +117,7 @@ describe Praxis::Response do
117
117
  end
118
118
 
119
119
  context 'multipart responses' do
120
- let(:part) { Praxis::MultipartPart.new('not so ok', {'Status' => 400, "Location" => "somewhere"}, {}) }
120
+ let(:part) { Praxis::MultipartPart.new('not so ok', {'Status' => 400, "Location" => "somewhere"}) }
121
121
 
122
122
  context '#add_part' do
123
123
 
@@ -8,7 +8,7 @@ describe Praxis::Responses::InternalServerError do
8
8
  it 'always sets the json content type' do
9
9
  expect(response.name).to be(:internal_server_error)
10
10
  expect(response.status).to be(500)
11
- expect(response.body).to be_empty
11
+ expect(response.body).to be_nil
12
12
  expect(response.headers).to have_key('Content-Type')
13
13
  expect(response.headers['Content-Type']).to eq('application/json')
14
14
  expect(response.instance_variable_get(:@error)).to be(nil)
@@ -52,7 +52,7 @@ describe Praxis::Responses::InternalServerError do
52
52
 
53
53
  subject(:response) { Praxis::Responses::InternalServerError.new(error: error) }
54
54
  before do
55
- expect(response.body).to be_empty
55
+ expect(response.body).to be_nil
56
56
  response.format!
57
57
  end
58
58
 
@@ -9,7 +9,7 @@ describe Praxis::Responses::ValidationError do
9
9
  it 'always sets the json content type' do
10
10
  expect(response.name).to be(:validation_error)
11
11
  expect(response.status).to be(400)
12
- expect(response.body).to be_empty
12
+ expect(response.body).to be_nil
13
13
  expect(response.headers).to have_key('Content-Type')
14
14
  expect(response.headers['Content-Type']).to eq('application/json')
15
15
  expect(response.instance_variable_get(:@errors)).to be(nil)
@@ -24,7 +24,7 @@ describe Praxis::Responses::ValidationError do
24
24
  let(:exception){ nil }
25
25
  subject(:response) { Praxis::Responses::ValidationError.new(summary: summary, errors: errors, exception: exception) }
26
26
  before do
27
- expect(response.body).to be_empty
27
+ expect(response.body).to be_nil
28
28
  end
29
29
  context 'when errors' do
30
30
  it 'it fills the errors key' do
@@ -6,7 +6,7 @@ describe Praxis::Router do
6
6
  let(:action){ double("action", resource_definition: resource_definition ) }
7
7
  let(:target){ double("target", action: action ) }
8
8
  let(:args){ {version: "1.0"} }
9
- subject(:matcher){ Praxis::Router::VersionMatcher.new(target,args) }
9
+ subject(:matcher){ Praxis::Router::VersionMatcher.new(target,**args) }
10
10
 
11
11
  context '.initialize' do
12
12
  let(:args){ {} }
@@ -73,7 +73,7 @@ class Instances < BaseClass
73
73
 
74
74
  headers = {
75
75
  'Status' => '201',
76
- 'Content-Type' => Instance.identifier + '+json',
76
+ 'Content-Type' => (Instance.identifier + '+json').to_s,
77
77
  'Location' => definition.to_href(cloud_id: cloud_id, id: instance.id)
78
78
  }
79
79
 
@@ -21,35 +21,17 @@ Praxis::Application.configure do |application|
21
21
  application.bootloader.use SimpleAuthenticationPlugin, config_file: 'config/authentication.yml'
22
22
  application.bootloader.use AuthorizationPlugin
23
23
 
24
-
25
- adapter_name = 'sqlite'
26
- db_name = ':memory:'
27
- connection_opts = if RUBY_PLATFORM !~ /java/
28
- { adapter: adapter_name , database: db_name }
29
- else
30
- require 'jdbc/sqlite3'
31
- { adapter: 'jdbc', uri: "jdbc:#{adapter_name}:#{db_name}" }
32
- end
33
-
34
- application.bootloader.use Praxis::Plugins::PraxisMapperPlugin, {
35
- config_data: {
36
- repositories: { default: connection_opts },
37
- log_stats: 'detailed'
38
- }
39
- }
40
-
41
24
  # enable "development-mode" options
42
25
  application.config.praxis.validate_responses = true
43
26
  application.config.praxis.validate_response_bodies = true
44
27
  application.config.praxis.show_exceptions = true
45
28
 
46
- # FIXME: until we have a better way to unit test such a feature...
47
29
  # Silly callback code pieces to test that the deferred callbacks work even for sub-stages
48
- application.bootloader.after :app, :models do
49
- PersonModel.identity(:other_id)
30
+ application.bootloader.after :app, :controllers do
31
+ $after_app_controllers = :worked
50
32
  end
51
33
  application.bootloader.after :app do
52
- raise "After sub-stage hooks not working!" unless PersonModel.identities.include? :other_id
34
+ raise "After sub-stage hooks not working!" unless $after_app_controllers == :worked
53
35
  end
54
36
 
55
37
 
@@ -19,26 +19,32 @@ require 'rack/test'
19
19
  require 'rspec/its'
20
20
  require 'rspec/collection_matchers'
21
21
 
22
-
23
-
24
22
  Dir["#{File.dirname(__FILE__)}/../lib/praxis/plugins/*.rb"].each do |file|
25
23
  require file
26
24
  end
27
25
 
26
+
28
27
  Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file|
29
28
  require file
30
29
  end
31
30
 
31
+ def suppress_output
32
+ original_stdout, original_stderr = $stdout.clone, $stderr.clone
33
+ $stderr.reopen File.new('/dev/null', 'w')
34
+ $stdout.reopen File.new('/dev/null', 'w')
35
+ yield
36
+ ensure
37
+ $stdout.reopen original_stdout
38
+ $stderr.reopen original_stderr
39
+ end
32
40
 
33
41
  RSpec.configure do |config|
34
42
  config.include Rack::Test::Methods
35
43
 
36
44
  config.before(:suite) do
45
+ Praxis::Mapper::Resource.finalize!
37
46
  Praxis::Blueprint.caching_enabled = true
38
47
  Praxis::Application.instance.setup(root:'spec/spec_app')
39
-
40
- # create the table
41
- setup_database!
42
48
  end
43
49
 
44
50
  config.before(:each) do
@@ -53,13 +59,3 @@ RSpec.configure do |config|
53
59
  end
54
60
  end
55
61
 
56
- # create the test db schema
57
- def setup_database!
58
- mapper = Praxis::Application.instance.plugins[:praxis_mapper]
59
- Sequel.connect(mapper.config.repositories["default"]['connection_settings'].dump) do |db|
60
- db.create_table! :people do
61
- primary_key :id
62
- string :name
63
- end
64
- end
65
- end
@@ -0,0 +1,39 @@
1
+ # Copied verbatim from: https://github.com/amogil/rspec-deep-ignore-order-matcher
2
+
3
+ RSpec::Matchers.define :be_deep_equal do |expected|
4
+ match { |actual| match? actual, expected }
5
+
6
+ failure_message do |actual|
7
+ "expected that #{actual} would be deep equal with #{expected}"
8
+ end
9
+
10
+ failure_message_when_negated do |actual|
11
+ "expected that #{actual} would not be deep equal with #{expected}"
12
+ end
13
+
14
+ description do
15
+ "be deep equal with #{expected}"
16
+ end
17
+
18
+ def match?(actual, expected)
19
+ return arrays_match?(actual, expected) if expected.is_a?(Array) && actual.is_a?(Array)
20
+ return hashes_match?(actual, expected) if expected.is_a?(Hash) && actual.is_a?(Hash)
21
+ expected == actual
22
+ end
23
+
24
+ def arrays_match?(actual, expected)
25
+ exp = expected.clone
26
+ actual.each do |a|
27
+ index = exp.find_index { |e| match? a, e }
28
+ return false if index.nil?
29
+ exp.delete_at(index)
30
+ end
31
+ exp.empty?
32
+ end
33
+
34
+ def hashes_match?(actual, expected)
35
+ return false unless actual.keys.sort == expected.keys.sort
36
+ actual.each { |key, value| return false unless match? value, expected[key] }
37
+ true
38
+ end
39
+ end
@@ -0,0 +1,124 @@
1
+ require 'ostruct'
2
+
3
+ require 'praxis/mapper/active_model_compat'
4
+ class SimpleModel < OpenStruct
5
+ include Praxis::Mapper::ActiveModelCompat
6
+ def self._praxis_associations
7
+ {
8
+ parent: {
9
+ model: ParentModel,
10
+ primary_key: :id,
11
+ type: :many_to_one,
12
+ local_key_columns: [:parent_id],
13
+ remote_key_columns: [:id]
14
+ },
15
+ other_model: {
16
+ model: OtherModel,
17
+ primary_key: :id,
18
+ type: :many_to_one,
19
+ local_key_columns: [:other_model_id],
20
+ remote_key_columns: [:id]
21
+ }
22
+ }
23
+ end
24
+ end
25
+
26
+ class OtherModel < OpenStruct
27
+ include Praxis::Mapper::ActiveModelCompat
28
+ def self._praxis_associations
29
+ {
30
+ parent: {
31
+ model: ParentModel,
32
+ primary_key: :id,
33
+ type: :many_to_one,
34
+ local_key_columns: [:parent_id],
35
+ remote_key_columns: [:id]
36
+ },
37
+ simple_models: {
38
+ model: SimpleModel,
39
+ primary_key: :id,
40
+ type: :many_to_many,
41
+ local_key_columns: [:id],
42
+ remote_key_columns: [:id] # The through table is in the middle where the FKs are...
43
+ }
44
+ }
45
+ end
46
+ end
47
+
48
+ class ParentModel < OpenStruct
49
+ include Praxis::Mapper::ActiveModelCompat
50
+ def self._praxis_associations
51
+ {
52
+ simple_children: {
53
+ model: SimpleModel,
54
+ primary_key: :id,
55
+ type: :one_to_many,
56
+ local_key_columns: [:id],
57
+ remote_key_columns: [:parent_id]
58
+ }
59
+ }
60
+ end
61
+ end
62
+
63
+ class YamlArrayModel < OpenStruct
64
+ include Praxis::Mapper::ActiveModelCompat
65
+ def self._praxis_associations
66
+ {
67
+ parents: {
68
+ model: ParentModel,
69
+ primary_key: :id,
70
+ type: :one_to_many,
71
+ local_key_columns: [:id],
72
+ remote_key_columns: [:parent_id]
73
+ }
74
+ }
75
+ end
76
+ end
77
+
78
+ # A set of resource classes for use in specs
79
+ class BaseResource < Praxis::Mapper::Resource
80
+ def href
81
+ base_href = '' # "/api"
82
+ base_href + "/#{self.class.collection_name}/#{self.id}"
83
+ end
84
+
85
+ property :href, dependencies: [:id]
86
+ end
87
+
88
+ class OtherResource < BaseResource
89
+ model OtherModel
90
+
91
+ property :display_name, dependencies: [:name]
92
+ end
93
+
94
+ class ParentResource < BaseResource
95
+ model ParentModel
96
+ end
97
+
98
+ class SimpleResource < BaseResource
99
+ model SimpleModel
100
+
101
+ resource_delegate :other_model => [:other_attribute]
102
+
103
+ def other_resource
104
+ self.other_model
105
+ end
106
+
107
+ property :aliased_method, dependencies: [:column1, :other_model]
108
+ property :other_resource, dependencies: [:other_model]
109
+
110
+ property :parent, dependencies: [:parent, :added_column]
111
+
112
+ property :name, dependencies: [:simple_name]
113
+ property :direct_other_name, dependencies: [ 'other_model.name' ]
114
+ property :aliased_other_name, dependencies: [ 'other_model.display_name' ]
115
+
116
+ property :everything, dependencies: [:*]
117
+ property :everything_from_parent, dependencies: ['parent.*']
118
+ property :circular_dep, dependencies: [ :circular_dep, :column1 ]
119
+ property :no_deps, dependencies: []
120
+ end
121
+
122
+ class YamlArrayResource < BaseResource
123
+ model YamlArrayModel
124
+ end