Runtime assertions for Ruby literal.fun
ruby
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #333 from yippee-fun/introspection

Introspection for properties and splat properties always 'default'

authored by

Stephen Ierodiaconou and committed by
GitHub
48216ed9 4ce9460e

+219
+59
lib/literal/properties/introspection.rb
··· 1 + # frozen_string_literal: true 2 + 3 + module Literal::Properties::Introspection 4 + def positional_properties 5 + literal_properties.filter(&:positional?) 6 + end 7 + 8 + def keyword_properties 9 + literal_properties.filter(&:keyword?) 10 + end 11 + 12 + def required_properties 13 + literal_properties.filter(&:required?) 14 + end 15 + 16 + def required_positional_properties 17 + required_properties.filter(&:positional?) 18 + end 19 + 20 + def required_keyword_properties 21 + required_properties.filter(&:keyword?) 22 + end 23 + 24 + def optional_positional_properties 25 + positional_properties - required_positional_properties 26 + end 27 + 28 + def optional_keyword_properties 29 + keyword_properties - required_keyword_properties 30 + end 31 + 32 + def positional_property_names 33 + positional_properties.map(&:name) 34 + end 35 + 36 + def keyword_property_names 37 + keyword_properties.map(&:name) 38 + end 39 + 40 + def required_property_names 41 + required_properties.map(&:name) 42 + end 43 + 44 + def required_positional_property_names 45 + required_positional_properties.map(&:name) 46 + end 47 + 48 + def required_keyword_property_names 49 + required_keyword_properties.map(&:name) 50 + end 51 + 52 + def optional_positional_property_names 53 + optional_positional_properties.map(&:name) 54 + end 55 + 56 + def optional_keyword_property_names 57 + optional_keyword_properties.map(&:name) 58 + end 59 + end
+1
lib/literal/property.rb
··· 51 51 end 52 52 53 53 def default? 54 + return true if splat? || double_splat? 54 55 nil != @default 55 56 end 56 57
+2
test/properties.test.rb
··· 46 46 refute_raises { example.new } 47 47 refute_raises { example.new("Hello") } 48 48 refute_raises { example.new("Hello", "World") } 49 + refute example.literal_properties[:example].required? { "Expected example to not be required" } 49 50 end 50 51 51 52 test "keyword splats are optional" do ··· 56 57 refute_raises { example.new } 57 58 refute_raises { example.new(example: "Hello") } 58 59 refute_raises { example.new(example: "Hello", world: "World") } 60 + refute example.literal_properties[:example].required? { "Expected example to not be required" } 59 61 end 60 62 61 63 test "block params are required by default" do
+157
test/properties/introspection.test.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class BasicIntrospection 4 + extend Literal::Properties 5 + extend Literal::Properties::Introspection 6 + 7 + prop :id, Integer, :positional 8 + prop :name, String, :positional 9 + prop :age, Integer 10 + prop :email, _Nilable(String) 11 + prop :friends, _Array(String), :* 12 + prop :options, _Hash(Symbol, String), :** 13 + prop :block, _Nilable(Proc), :& 14 + end 15 + 16 + class WithOptionals 17 + extend Literal::Properties 18 + extend Literal::Properties::Introspection 19 + 20 + prop :required_pos, String, :positional 21 + prop :optional_pos, String, :positional, default: "default" 22 + prop :optional_name, _Nilable(String), :positional 23 + prop :required_kw, Integer 24 + prop :optional_kw, Integer, default: 42 25 + prop :tags, _Array(String), default: -> { [] } 26 + prop :created_at, _Nilable(Time) 27 + end 28 + 29 + class EmptyWithIntrospection 30 + extend Literal::Properties 31 + extend Literal::Properties::Introspection 32 + end 33 + 34 + test "positional_properties returns all positional properties" do 35 + props = BasicIntrospection.positional_properties 36 + assert_equal props.map(&:name), [:id, :name] 37 + assert props.all?(&:positional?) 38 + end 39 + 40 + test "positional_property_names returns all positional property names" do 41 + names = BasicIntrospection.positional_property_names 42 + assert_equal names, [:id, :name] 43 + end 44 + 45 + test "keyword_properties returns all keyword properties" do 46 + props = BasicIntrospection.keyword_properties 47 + assert_equal props.map(&:name), [:age, :email] 48 + assert props.all?(&:keyword?) 49 + end 50 + 51 + test "keyword_property_names returns all keyword property names" do 52 + names = BasicIntrospection.keyword_property_names 53 + assert_equal names, [:age, :email] 54 + end 55 + 56 + test "required_properties returns all required properties" do 57 + props = BasicIntrospection.required_properties 58 + assert_equal props.map(&:name), [:id, :name, :age] 59 + assert props.all?(&:required?) 60 + end 61 + 62 + test "required_property_names returns all required property names" do 63 + names = BasicIntrospection.required_property_names 64 + assert_equal names, [:id, :name, :age] 65 + end 66 + 67 + test "required_positional_properties returns only required positional properties" do 68 + props = BasicIntrospection.required_positional_properties 69 + assert_equal props.map(&:name), [:id, :name] 70 + assert props.all? { |p| p.required? && p.positional? } 71 + end 72 + 73 + test "required_positional_property_names returns only required positional property names" do 74 + names = BasicIntrospection.required_positional_property_names 75 + assert_equal names, [:id, :name] 76 + end 77 + 78 + test "required_keyword_properties returns only required keyword properties" do 79 + props = BasicIntrospection.required_keyword_properties 80 + assert_equal props.map(&:name), [:age] 81 + assert props.all? { |p| p.required? && p.keyword? } 82 + end 83 + 84 + test "required_keyword_property_names returns only required keyword property names" do 85 + names = BasicIntrospection.required_keyword_property_names 86 + assert_equal names, [:age] 87 + end 88 + 89 + test "optional_positional_properties returns positional properties that are not required" do 90 + props = WithOptionals.optional_positional_properties 91 + assert_equal props.map(&:name), [:optional_pos, :optional_name] 92 + assert props.all? { |p| p.positional? && !p.required? } 93 + end 94 + 95 + test "optional_positional_property_names returns optional positional property names" do 96 + names = WithOptionals.optional_positional_property_names 97 + assert_equal names, [:optional_pos, :optional_name] 98 + end 99 + 100 + test "optional_keyword_properties returns keyword properties that are not required" do 101 + props = WithOptionals.optional_keyword_properties 102 + assert_equal props.map(&:name), [:optional_kw, :tags, :created_at] 103 + assert props.all? { |p| p.keyword? && !p.required? } 104 + end 105 + 106 + test "optional_keyword_property_names returns optional keyword property names" do 107 + names = WithOptionals.optional_keyword_property_names 108 + assert_equal names, [:optional_kw, :tags, :created_at] 109 + end 110 + 111 + test "empty class returns empty arrays for all methods" do 112 + assert_equal EmptyWithIntrospection.positional_properties, [] 113 + assert_equal EmptyWithIntrospection.keyword_properties, [] 114 + assert_equal EmptyWithIntrospection.required_properties, [] 115 + assert_equal EmptyWithIntrospection.required_positional_properties, [] 116 + assert_equal EmptyWithIntrospection.required_keyword_properties, [] 117 + assert_equal EmptyWithIntrospection.optional_positional_properties, [] 118 + assert_equal EmptyWithIntrospection.optional_keyword_properties, [] 119 + 120 + assert_equal EmptyWithIntrospection.positional_property_names, [] 121 + assert_equal EmptyWithIntrospection.keyword_property_names, [] 122 + assert_equal EmptyWithIntrospection.required_property_names, [] 123 + assert_equal EmptyWithIntrospection.required_positional_property_names, [] 124 + assert_equal EmptyWithIntrospection.required_keyword_property_names, [] 125 + assert_equal EmptyWithIntrospection.optional_positional_property_names, [] 126 + assert_equal EmptyWithIntrospection.optional_keyword_property_names, [] 127 + end 128 + 129 + test "splat parameters are not included in positional or keyword properties" do 130 + positional_names = BasicIntrospection.positional_property_names 131 + refute positional_names.include?(:friends) 132 + 133 + keyword_names = BasicIntrospection.keyword_property_names 134 + refute keyword_names.include?(:options) 135 + end 136 + 137 + test "block parameters are not included in any property lists" do 138 + all_names = BasicIntrospection.positional_property_names + BasicIntrospection.keyword_property_names 139 + refute all_names.include?(:block) 140 + end 141 + 142 + test "nilable positional properties are considered optional" do 143 + required_names = WithOptionals.required_positional_property_names 144 + optional_names = WithOptionals.optional_positional_property_names 145 + 146 + assert_equal required_names, [:required_pos] 147 + assert_equal optional_names, [:optional_pos, :optional_name] 148 + end 149 + 150 + test "mixed property types with defaults and nilables" do 151 + assert_equal WithOptionals.positional_property_names, [:required_pos, :optional_pos, :optional_name] 152 + assert_equal WithOptionals.keyword_property_names, [:required_kw, :optional_kw, :tags, :created_at] 153 + assert_equal WithOptionals.required_positional_property_names, [:required_pos] 154 + assert_equal WithOptionals.required_keyword_property_names, [:required_kw] 155 + assert_equal WithOptionals.optional_positional_property_names, [:optional_pos, :optional_name] 156 + assert_equal WithOptionals.optional_keyword_property_names, [:optional_kw, :tags, :created_at] 157 + end